##// END OF EJS Templates
codemirror: bumped to version 5.49.2
marcink -
r4105:10488616 default
parent child Browse files
Show More
@@ -0,0 +1,173 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11 })(function(CodeMirror) {
12 "use strict";
13
14 CodeMirror.defineMode("fcl", function(config) {
15 var indentUnit = config.indentUnit;
16
17 var keywords = {
18 "term": true,
19 "method": true, "accu": true,
20 "rule": true, "then": true, "is": true, "and": true, "or": true,
21 "if": true, "default": true
22 };
23
24 var start_blocks = {
25 "var_input": true,
26 "var_output": true,
27 "fuzzify": true,
28 "defuzzify": true,
29 "function_block": true,
30 "ruleblock": true
31 };
32
33 var end_blocks = {
34 "end_ruleblock": true,
35 "end_defuzzify": true,
36 "end_function_block": true,
37 "end_fuzzify": true,
38 "end_var": true
39 };
40
41 var atoms = {
42 "true": true, "false": true, "nan": true,
43 "real": true, "min": true, "max": true, "cog": true, "cogs": true
44 };
45
46 var isOperatorChar = /[+\-*&^%:=<>!|\/]/;
47
48 function tokenBase(stream, state) {
49 var ch = stream.next();
50
51 if (/[\d\.]/.test(ch)) {
52 if (ch == ".") {
53 stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
54 } else if (ch == "0") {
55 stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
56 } else {
57 stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
58 }
59 return "number";
60 }
61
62 if (ch == "/" || ch == "(") {
63 if (stream.eat("*")) {
64 state.tokenize = tokenComment;
65 return tokenComment(stream, state);
66 }
67 if (stream.eat("/")) {
68 stream.skipToEnd();
69 return "comment";
70 }
71 }
72 if (isOperatorChar.test(ch)) {
73 stream.eatWhile(isOperatorChar);
74 return "operator";
75 }
76 stream.eatWhile(/[\w\$_\xa1-\uffff]/);
77
78 var cur = stream.current().toLowerCase();
79 if (keywords.propertyIsEnumerable(cur) ||
80 start_blocks.propertyIsEnumerable(cur) ||
81 end_blocks.propertyIsEnumerable(cur)) {
82 return "keyword";
83 }
84 if (atoms.propertyIsEnumerable(cur)) return "atom";
85 return "variable";
86 }
87
88
89 function tokenComment(stream, state) {
90 var maybeEnd = false, ch;
91 while (ch = stream.next()) {
92 if ((ch == "/" || ch == ")") && maybeEnd) {
93 state.tokenize = tokenBase;
94 break;
95 }
96 maybeEnd = (ch == "*");
97 }
98 return "comment";
99 }
100
101 function Context(indented, column, type, align, prev) {
102 this.indented = indented;
103 this.column = column;
104 this.type = type;
105 this.align = align;
106 this.prev = prev;
107 }
108
109 function pushContext(state, col, type) {
110 return state.context = new Context(state.indented, col, type, null, state.context);
111 }
112
113 function popContext(state) {
114 if (!state.context.prev) return;
115 var t = state.context.type;
116 if (t == "end_block")
117 state.indented = state.context.indented;
118 return state.context = state.context.prev;
119 }
120
121 // Interface
122
123 return {
124 startState: function(basecolumn) {
125 return {
126 tokenize: null,
127 context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
128 indented: 0,
129 startOfLine: true
130 };
131 },
132
133 token: function(stream, state) {
134 var ctx = state.context;
135 if (stream.sol()) {
136 if (ctx.align == null) ctx.align = false;
137 state.indented = stream.indentation();
138 state.startOfLine = true;
139 }
140 if (stream.eatSpace()) return null;
141
142 var style = (state.tokenize || tokenBase)(stream, state);
143 if (style == "comment") return style;
144 if (ctx.align == null) ctx.align = true;
145
146 var cur = stream.current().toLowerCase();
147
148 if (start_blocks.propertyIsEnumerable(cur)) pushContext(state, stream.column(), "end_block");
149 else if (end_blocks.propertyIsEnumerable(cur)) popContext(state);
150
151 state.startOfLine = false;
152 return style;
153 },
154
155 indent: function(state, textAfter) {
156 if (state.tokenize != tokenBase && state.tokenize != null) return 0;
157 var ctx = state.context;
158
159 var closing = end_blocks.propertyIsEnumerable(textAfter);
160 if (ctx.align) return ctx.column + (closing ? 0 : 1);
161 else return ctx.indented + (closing ? 0 : indentUnit);
162 },
163
164 electricChars: "ryk",
165 fold: "brace",
166 blockCommentStart: "(*",
167 blockCommentEnd: "*)",
168 lineComment: "//"
169 };
170 });
171
172 CodeMirror.defineMIME("text/x-fcl", "fcl");
173 });
@@ -0,0 +1,129 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11 })(function(CodeMirror) {
12 "use strict";
13
14 var rfc2822 = [
15 "From", "Sender", "Reply-To", "To", "Cc", "Bcc", "Message-ID",
16 "In-Reply-To", "References", "Resent-From", "Resent-Sender", "Resent-To",
17 "Resent-Cc", "Resent-Bcc", "Resent-Message-ID", "Return-Path", "Received"
18 ];
19 var rfc2822NoEmail = [
20 "Date", "Subject", "Comments", "Keywords", "Resent-Date"
21 ];
22
23 CodeMirror.registerHelper("hintWords", "mbox", rfc2822.concat(rfc2822NoEmail));
24
25 var whitespace = /^[ \t]/;
26 var separator = /^From /; // See RFC 4155
27 var rfc2822Header = new RegExp("^(" + rfc2822.join("|") + "): ");
28 var rfc2822HeaderNoEmail = new RegExp("^(" + rfc2822NoEmail.join("|") + "): ");
29 var header = /^[^:]+:/; // Optional fields defined in RFC 2822
30 var email = /^[^ ]+@[^ ]+/;
31 var untilEmail = /^.*?(?=[^ ]+?@[^ ]+)/;
32 var bracketedEmail = /^<.*?>/;
33 var untilBracketedEmail = /^.*?(?=<.*>)/;
34
35 function styleForHeader(header) {
36 if (header === "Subject") return "header";
37 return "string";
38 }
39
40 function readToken(stream, state) {
41 if (stream.sol()) {
42 // From last line
43 state.inSeparator = false;
44 if (state.inHeader && stream.match(whitespace)) {
45 // Header folding
46 return null;
47 } else {
48 state.inHeader = false;
49 state.header = null;
50 }
51
52 if (stream.match(separator)) {
53 state.inHeaders = true;
54 state.inSeparator = true;
55 return "atom";
56 }
57
58 var match;
59 var emailPermitted = false;
60 if ((match = stream.match(rfc2822HeaderNoEmail)) ||
61 (emailPermitted = true) && (match = stream.match(rfc2822Header))) {
62 state.inHeaders = true;
63 state.inHeader = true;
64 state.emailPermitted = emailPermitted;
65 state.header = match[1];
66 return "atom";
67 }
68
69 // Use vim's heuristics: recognize custom headers only if the line is in a
70 // block of legitimate headers.
71 if (state.inHeaders && (match = stream.match(header))) {
72 state.inHeader = true;
73 state.emailPermitted = true;
74 state.header = match[1];
75 return "atom";
76 }
77
78 state.inHeaders = false;
79 stream.skipToEnd();
80 return null;
81 }
82
83 if (state.inSeparator) {
84 if (stream.match(email)) return "link";
85 if (stream.match(untilEmail)) return "atom";
86 stream.skipToEnd();
87 return "atom";
88 }
89
90 if (state.inHeader) {
91 var style = styleForHeader(state.header);
92
93 if (state.emailPermitted) {
94 if (stream.match(bracketedEmail)) return style + " link";
95 if (stream.match(untilBracketedEmail)) return style;
96 }
97 stream.skipToEnd();
98 return style;
99 }
100
101 stream.skipToEnd();
102 return null;
103 };
104
105 CodeMirror.defineMode("mbox", function() {
106 return {
107 startState: function() {
108 return {
109 // Is in a mbox separator
110 inSeparator: false,
111 // Is in a mail header
112 inHeader: false,
113 // If bracketed email is permitted. Only applicable when inHeader
114 emailPermitted: false,
115 // Name of current header
116 header: null,
117 // Is in a region of mail headers
118 inHeaders: false
119 };
120 },
121 token: readToken,
122 blankLine: function(state) {
123 state.inHeaders = state.inSeparator = state.inHeader = false;
124 }
125 };
126 });
127
128 CodeMirror.defineMIME("application/mbox", "mbox");
129 });
@@ -0,0 +1,398 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 (function(mod) {
5 'use strict';
6 if (typeof exports == 'object' && typeof module == 'object') // CommonJS
7 mod(require('../../lib/codemirror'));
8 else if (typeof define == 'function' && define.amd) // AMD
9 define(['../../lib/codemirror'], mod);
10 else // Plain browser env
11 mod(window.CodeMirror);
12 })(function(CodeMirror) {
13 'use strict';
14
15 CodeMirror.defineMode('powershell', function() {
16 function buildRegexp(patterns, options) {
17 options = options || {};
18 var prefix = options.prefix !== undefined ? options.prefix : '^';
19 var suffix = options.suffix !== undefined ? options.suffix : '\\b';
20
21 for (var i = 0; i < patterns.length; i++) {
22 if (patterns[i] instanceof RegExp) {
23 patterns[i] = patterns[i].source;
24 }
25 else {
26 patterns[i] = patterns[i].replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
27 }
28 }
29
30 return new RegExp(prefix + '(' + patterns.join('|') + ')' + suffix, 'i');
31 }
32
33 var notCharacterOrDash = '(?=[^A-Za-z\\d\\-_]|$)';
34 var varNames = /[\w\-:]/
35 var keywords = buildRegexp([
36 /begin|break|catch|continue|data|default|do|dynamicparam/,
37 /else|elseif|end|exit|filter|finally|for|foreach|from|function|if|in/,
38 /param|process|return|switch|throw|trap|try|until|where|while/
39 ], { suffix: notCharacterOrDash });
40
41 var punctuation = /[\[\]{},;`\.]|@[({]/;
42 var wordOperators = buildRegexp([
43 'f',
44 /b?not/,
45 /[ic]?split/, 'join',
46 /is(not)?/, 'as',
47 /[ic]?(eq|ne|[gl][te])/,
48 /[ic]?(not)?(like|match|contains)/,
49 /[ic]?replace/,
50 /b?(and|or|xor)/
51 ], { prefix: '-' });
52 var symbolOperators = /[+\-*\/%]=|\+\+|--|\.\.|[+\-*&^%:=!|\/]|<(?!#)|(?!#)>/;
53 var operators = buildRegexp([wordOperators, symbolOperators], { suffix: '' });
54
55 var numbers = /^((0x[\da-f]+)|((\d+\.\d+|\d\.|\.\d+|\d+)(e[\+\-]?\d+)?))[ld]?([kmgtp]b)?/i;
56
57 var identifiers = /^[A-Za-z\_][A-Za-z\-\_\d]*\b/;
58
59 var symbolBuiltins = /[A-Z]:|%|\?/i;
60 var namedBuiltins = buildRegexp([
61 /Add-(Computer|Content|History|Member|PSSnapin|Type)/,
62 /Checkpoint-Computer/,
63 /Clear-(Content|EventLog|History|Host|Item(Property)?|Variable)/,
64 /Compare-Object/,
65 /Complete-Transaction/,
66 /Connect-PSSession/,
67 /ConvertFrom-(Csv|Json|SecureString|StringData)/,
68 /Convert-Path/,
69 /ConvertTo-(Csv|Html|Json|SecureString|Xml)/,
70 /Copy-Item(Property)?/,
71 /Debug-Process/,
72 /Disable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)/,
73 /Disconnect-PSSession/,
74 /Enable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)/,
75 /(Enter|Exit)-PSSession/,
76 /Export-(Alias|Clixml|Console|Counter|Csv|FormatData|ModuleMember|PSSession)/,
77 /ForEach-Object/,
78 /Format-(Custom|List|Table|Wide)/,
79 new RegExp('Get-(Acl|Alias|AuthenticodeSignature|ChildItem|Command|ComputerRestorePoint|Content|ControlPanelItem|Counter|Credential'
80 + '|Culture|Date|Event|EventLog|EventSubscriber|ExecutionPolicy|FormatData|Help|History|Host|HotFix|Item|ItemProperty|Job'
81 + '|Location|Member|Module|PfxCertificate|Process|PSBreakpoint|PSCallStack|PSDrive|PSProvider|PSSession|PSSessionConfiguration'
82 + '|PSSnapin|Random|Service|TraceSource|Transaction|TypeData|UICulture|Unique|Variable|Verb|WinEvent|WmiObject)'),
83 /Group-Object/,
84 /Import-(Alias|Clixml|Counter|Csv|LocalizedData|Module|PSSession)/,
85 /ImportSystemModules/,
86 /Invoke-(Command|Expression|History|Item|RestMethod|WebRequest|WmiMethod)/,
87 /Join-Path/,
88 /Limit-EventLog/,
89 /Measure-(Command|Object)/,
90 /Move-Item(Property)?/,
91 new RegExp('New-(Alias|Event|EventLog|Item(Property)?|Module|ModuleManifest|Object|PSDrive|PSSession|PSSessionConfigurationFile'
92 + '|PSSessionOption|PSTransportOption|Service|TimeSpan|Variable|WebServiceProxy|WinEvent)'),
93 /Out-(Default|File|GridView|Host|Null|Printer|String)/,
94 /Pause/,
95 /(Pop|Push)-Location/,
96 /Read-Host/,
97 /Receive-(Job|PSSession)/,
98 /Register-(EngineEvent|ObjectEvent|PSSessionConfiguration|WmiEvent)/,
99 /Remove-(Computer|Event|EventLog|Item(Property)?|Job|Module|PSBreakpoint|PSDrive|PSSession|PSSnapin|TypeData|Variable|WmiObject)/,
100 /Rename-(Computer|Item(Property)?)/,
101 /Reset-ComputerMachinePassword/,
102 /Resolve-Path/,
103 /Restart-(Computer|Service)/,
104 /Restore-Computer/,
105 /Resume-(Job|Service)/,
106 /Save-Help/,
107 /Select-(Object|String|Xml)/,
108 /Send-MailMessage/,
109 new RegExp('Set-(Acl|Alias|AuthenticodeSignature|Content|Date|ExecutionPolicy|Item(Property)?|Location|PSBreakpoint|PSDebug' +
110 '|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)'),
111 /Show-(Command|ControlPanelItem|EventLog)/,
112 /Sort-Object/,
113 /Split-Path/,
114 /Start-(Job|Process|Service|Sleep|Transaction|Transcript)/,
115 /Stop-(Computer|Job|Process|Service|Transcript)/,
116 /Suspend-(Job|Service)/,
117 /TabExpansion2/,
118 /Tee-Object/,
119 /Test-(ComputerSecureChannel|Connection|ModuleManifest|Path|PSSessionConfigurationFile)/,
120 /Trace-Command/,
121 /Unblock-File/,
122 /Undo-Transaction/,
123 /Unregister-(Event|PSSessionConfiguration)/,
124 /Update-(FormatData|Help|List|TypeData)/,
125 /Use-Transaction/,
126 /Wait-(Event|Job|Process)/,
127 /Where-Object/,
128 /Write-(Debug|Error|EventLog|Host|Output|Progress|Verbose|Warning)/,
129 /cd|help|mkdir|more|oss|prompt/,
130 /ac|asnp|cat|cd|chdir|clc|clear|clhy|cli|clp|cls|clv|cnsn|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|dnsn|ebp/,
131 /echo|epal|epcsv|epsn|erase|etsn|exsn|fc|fl|foreach|ft|fw|gal|gbp|gc|gci|gcm|gcs|gdr|ghy|gi|gjb|gl|gm|gmo|gp|gps/,
132 /group|gsn|gsnp|gsv|gu|gv|gwmi|h|history|icm|iex|ihy|ii|ipal|ipcsv|ipmo|ipsn|irm|ise|iwmi|iwr|kill|lp|ls|man|md/,
133 /measure|mi|mount|move|mp|mv|nal|ndr|ni|nmo|npssc|nsn|nv|ogv|oh|popd|ps|pushd|pwd|r|rbp|rcjb|rcsn|rd|rdr|ren|ri/,
134 /rjb|rm|rmdir|rmo|rni|rnp|rp|rsn|rsnp|rujb|rv|rvpa|rwmi|sajb|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls/,
135 /sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|where|wjb|write/
136 ], { prefix: '', suffix: '' });
137 var variableBuiltins = buildRegexp([
138 /[$?^_]|Args|ConfirmPreference|ConsoleFileName|DebugPreference|Error|ErrorActionPreference|ErrorView|ExecutionContext/,
139 /FormatEnumerationLimit|Home|Host|Input|MaximumAliasCount|MaximumDriveCount|MaximumErrorCount|MaximumFunctionCount/,
140 /MaximumHistoryCount|MaximumVariableCount|MyInvocation|NestedPromptLevel|OutputEncoding|Pid|Profile|ProgressPreference/,
141 /PSBoundParameters|PSCommandPath|PSCulture|PSDefaultParameterValues|PSEmailServer|PSHome|PSScriptRoot|PSSessionApplicationName/,
142 /PSSessionConfigurationName|PSSessionOption|PSUICulture|PSVersionTable|Pwd|ShellId|StackTrace|VerbosePreference/,
143 /WarningPreference|WhatIfPreference/,
144
145 /Event|EventArgs|EventSubscriber|Sender/,
146 /Matches|Ofs|ForEach|LastExitCode|PSCmdlet|PSItem|PSSenderInfo|This/,
147 /true|false|null/
148 ], { prefix: '\\$', suffix: '' });
149
150 var builtins = buildRegexp([symbolBuiltins, namedBuiltins, variableBuiltins], { suffix: notCharacterOrDash });
151
152 var grammar = {
153 keyword: keywords,
154 number: numbers,
155 operator: operators,
156 builtin: builtins,
157 punctuation: punctuation,
158 identifier: identifiers
159 };
160
161 // tokenizers
162 function tokenBase(stream, state) {
163 // Handle Comments
164 //var ch = stream.peek();
165
166 var parent = state.returnStack[state.returnStack.length - 1];
167 if (parent && parent.shouldReturnFrom(state)) {
168 state.tokenize = parent.tokenize;
169 state.returnStack.pop();
170 return state.tokenize(stream, state);
171 }
172
173 if (stream.eatSpace()) {
174 return null;
175 }
176
177 if (stream.eat('(')) {
178 state.bracketNesting += 1;
179 return 'punctuation';
180 }
181
182 if (stream.eat(')')) {
183 state.bracketNesting -= 1;
184 return 'punctuation';
185 }
186
187 for (var key in grammar) {
188 if (stream.match(grammar[key])) {
189 return key;
190 }
191 }
192
193 var ch = stream.next();
194
195 // single-quote string
196 if (ch === "'") {
197 return tokenSingleQuoteString(stream, state);
198 }
199
200 if (ch === '$') {
201 return tokenVariable(stream, state);
202 }
203
204 // double-quote string
205 if (ch === '"') {
206 return tokenDoubleQuoteString(stream, state);
207 }
208
209 if (ch === '<' && stream.eat('#')) {
210 state.tokenize = tokenComment;
211 return tokenComment(stream, state);
212 }
213
214 if (ch === '#') {
215 stream.skipToEnd();
216 return 'comment';
217 }
218
219 if (ch === '@') {
220 var quoteMatch = stream.eat(/["']/);
221 if (quoteMatch && stream.eol()) {
222 state.tokenize = tokenMultiString;
223 state.startQuote = quoteMatch[0];
224 return tokenMultiString(stream, state);
225 } else if (stream.eol()) {
226 return 'error';
227 } else if (stream.peek().match(/[({]/)) {
228 return 'punctuation';
229 } else if (stream.peek().match(varNames)) {
230 // splatted variable
231 return tokenVariable(stream, state);
232 }
233 }
234 return 'error';
235 }
236
237 function tokenSingleQuoteString(stream, state) {
238 var ch;
239 while ((ch = stream.peek()) != null) {
240 stream.next();
241
242 if (ch === "'" && !stream.eat("'")) {
243 state.tokenize = tokenBase;
244 return 'string';
245 }
246 }
247
248 return 'error';
249 }
250
251 function tokenDoubleQuoteString(stream, state) {
252 var ch;
253 while ((ch = stream.peek()) != null) {
254 if (ch === '$') {
255 state.tokenize = tokenStringInterpolation;
256 return 'string';
257 }
258
259 stream.next();
260 if (ch === '`') {
261 stream.next();
262 continue;
263 }
264
265 if (ch === '"' && !stream.eat('"')) {
266 state.tokenize = tokenBase;
267 return 'string';
268 }
269 }
270
271 return 'error';
272 }
273
274 function tokenStringInterpolation(stream, state) {
275 return tokenInterpolation(stream, state, tokenDoubleQuoteString);
276 }
277
278 function tokenMultiStringReturn(stream, state) {
279 state.tokenize = tokenMultiString;
280 state.startQuote = '"'
281 return tokenMultiString(stream, state);
282 }
283
284 function tokenHereStringInterpolation(stream, state) {
285 return tokenInterpolation(stream, state, tokenMultiStringReturn);
286 }
287
288 function tokenInterpolation(stream, state, parentTokenize) {
289 if (stream.match('$(')) {
290 var savedBracketNesting = state.bracketNesting;
291 state.returnStack.push({
292 /*jshint loopfunc:true */
293 shouldReturnFrom: function(state) {
294 return state.bracketNesting === savedBracketNesting;
295 },
296 tokenize: parentTokenize
297 });
298 state.tokenize = tokenBase;
299 state.bracketNesting += 1;
300 return 'punctuation';
301 } else {
302 stream.next();
303 state.returnStack.push({
304 shouldReturnFrom: function() { return true; },
305 tokenize: parentTokenize
306 });
307 state.tokenize = tokenVariable;
308 return state.tokenize(stream, state);
309 }
310 }
311
312 function tokenComment(stream, state) {
313 var maybeEnd = false, ch;
314 while ((ch = stream.next()) != null) {
315 if (maybeEnd && ch == '>') {
316 state.tokenize = tokenBase;
317 break;
318 }
319 maybeEnd = (ch === '#');
320 }
321 return 'comment';
322 }
323
324 function tokenVariable(stream, state) {
325 var ch = stream.peek();
326 if (stream.eat('{')) {
327 state.tokenize = tokenVariableWithBraces;
328 return tokenVariableWithBraces(stream, state);
329 } else if (ch != undefined && ch.match(varNames)) {
330 stream.eatWhile(varNames);
331 state.tokenize = tokenBase;
332 return 'variable-2';
333 } else {
334 state.tokenize = tokenBase;
335 return 'error';
336 }
337 }
338
339 function tokenVariableWithBraces(stream, state) {
340 var ch;
341 while ((ch = stream.next()) != null) {
342 if (ch === '}') {
343 state.tokenize = tokenBase;
344 break;
345 }
346 }
347 return 'variable-2';
348 }
349
350 function tokenMultiString(stream, state) {
351 var quote = state.startQuote;
352 if (stream.sol() && stream.match(new RegExp(quote + '@'))) {
353 state.tokenize = tokenBase;
354 }
355 else if (quote === '"') {
356 while (!stream.eol()) {
357 var ch = stream.peek();
358 if (ch === '$') {
359 state.tokenize = tokenHereStringInterpolation;
360 return 'string';
361 }
362
363 stream.next();
364 if (ch === '`') {
365 stream.next();
366 }
367 }
368 }
369 else {
370 stream.skipToEnd();
371 }
372
373 return 'string';
374 }
375
376 var external = {
377 startState: function() {
378 return {
379 returnStack: [],
380 bracketNesting: 0,
381 tokenize: tokenBase
382 };
383 },
384
385 token: function(stream, state) {
386 return state.tokenize(stream, state);
387 },
388
389 blockCommentStart: '<#',
390 blockCommentEnd: '#>',
391 lineComment: '#',
392 fold: 'brace'
393 };
394 return external;
395 });
396
397 CodeMirror.defineMIME('application/x-powershell', 'powershell');
398 });
@@ -0,0 +1,69 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11 })(function(CodeMirror) {
12 "use strict";
13
14 function wordRegexp(words) {
15 return new RegExp("^((" + words.join(")|(") + "))\\b", "i");
16 };
17
18 var keywordArray = [
19 "package", "message", "import", "syntax",
20 "required", "optional", "repeated", "reserved", "default", "extensions", "packed",
21 "bool", "bytes", "double", "enum", "float", "string",
22 "int32", "int64", "uint32", "uint64", "sint32", "sint64", "fixed32", "fixed64", "sfixed32", "sfixed64",
23 "option", "service", "rpc", "returns"
24 ];
25 var keywords = wordRegexp(keywordArray);
26
27 CodeMirror.registerHelper("hintWords", "protobuf", keywordArray);
28
29 var identifiers = new RegExp("^[_A-Za-z\xa1-\uffff][_A-Za-z0-9\xa1-\uffff]*");
30
31 function tokenBase(stream) {
32 // whitespaces
33 if (stream.eatSpace()) return null;
34
35 // Handle one line Comments
36 if (stream.match("//")) {
37 stream.skipToEnd();
38 return "comment";
39 }
40
41 // Handle Number Literals
42 if (stream.match(/^[0-9\.+-]/, false)) {
43 if (stream.match(/^[+-]?0x[0-9a-fA-F]+/))
44 return "number";
45 if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?/))
46 return "number";
47 if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?/))
48 return "number";
49 }
50
51 // Handle Strings
52 if (stream.match(/^"([^"]|(""))*"/)) { return "string"; }
53 if (stream.match(/^'([^']|(''))*'/)) { return "string"; }
54
55 // Handle words
56 if (stream.match(keywords)) { return "keyword"; }
57 if (stream.match(identifiers)) { return "variable"; } ;
58
59 // Handle non-detected items
60 stream.next();
61 return null;
62 };
63
64 CodeMirror.defineMode("protobuf", function() {
65 return {token: tokenBase};
66 });
67
68 CodeMirror.defineMIME("text/x-protobuf", "protobuf");
69 });
This diff has been collapsed as it changes many lines, (591 lines changed) Show them Hide them
@@ -0,0 +1,591 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"), require("../javascript/javascript"), require("../css/css"), require("../htmlmixed/htmlmixed"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror", "../javascript/javascript", "../css/css", "../htmlmixed/htmlmixed"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11 })(function(CodeMirror) {
12 "use strict";
13
14 CodeMirror.defineMode("pug", function (config) {
15 // token types
16 var KEYWORD = 'keyword';
17 var DOCTYPE = 'meta';
18 var ID = 'builtin';
19 var CLASS = 'qualifier';
20
21 var ATTRS_NEST = {
22 '{': '}',
23 '(': ')',
24 '[': ']'
25 };
26
27 var jsMode = CodeMirror.getMode(config, 'javascript');
28
29 function State() {
30 this.javaScriptLine = false;
31 this.javaScriptLineExcludesColon = false;
32
33 this.javaScriptArguments = false;
34 this.javaScriptArgumentsDepth = 0;
35
36 this.isInterpolating = false;
37 this.interpolationNesting = 0;
38
39 this.jsState = CodeMirror.startState(jsMode);
40
41 this.restOfLine = '';
42
43 this.isIncludeFiltered = false;
44 this.isEach = false;
45
46 this.lastTag = '';
47 this.scriptType = '';
48
49 // Attributes Mode
50 this.isAttrs = false;
51 this.attrsNest = [];
52 this.inAttributeName = true;
53 this.attributeIsType = false;
54 this.attrValue = '';
55
56 // Indented Mode
57 this.indentOf = Infinity;
58 this.indentToken = '';
59
60 this.innerMode = null;
61 this.innerState = null;
62
63 this.innerModeForLine = false;
64 }
65 /**
66 * Safely copy a state
67 *
68 * @return {State}
69 */
70 State.prototype.copy = function () {
71 var res = new State();
72 res.javaScriptLine = this.javaScriptLine;
73 res.javaScriptLineExcludesColon = this.javaScriptLineExcludesColon;
74 res.javaScriptArguments = this.javaScriptArguments;
75 res.javaScriptArgumentsDepth = this.javaScriptArgumentsDepth;
76 res.isInterpolating = this.isInterpolating;
77 res.interpolationNesting = this.interpolationNesting;
78
79 res.jsState = CodeMirror.copyState(jsMode, this.jsState);
80
81 res.innerMode = this.innerMode;
82 if (this.innerMode && this.innerState) {
83 res.innerState = CodeMirror.copyState(this.innerMode, this.innerState);
84 }
85
86 res.restOfLine = this.restOfLine;
87
88 res.isIncludeFiltered = this.isIncludeFiltered;
89 res.isEach = this.isEach;
90 res.lastTag = this.lastTag;
91 res.scriptType = this.scriptType;
92 res.isAttrs = this.isAttrs;
93 res.attrsNest = this.attrsNest.slice();
94 res.inAttributeName = this.inAttributeName;
95 res.attributeIsType = this.attributeIsType;
96 res.attrValue = this.attrValue;
97 res.indentOf = this.indentOf;
98 res.indentToken = this.indentToken;
99
100 res.innerModeForLine = this.innerModeForLine;
101
102 return res;
103 };
104
105 function javaScript(stream, state) {
106 if (stream.sol()) {
107 // if javaScriptLine was set at end of line, ignore it
108 state.javaScriptLine = false;
109 state.javaScriptLineExcludesColon = false;
110 }
111 if (state.javaScriptLine) {
112 if (state.javaScriptLineExcludesColon && stream.peek() === ':') {
113 state.javaScriptLine = false;
114 state.javaScriptLineExcludesColon = false;
115 return;
116 }
117 var tok = jsMode.token(stream, state.jsState);
118 if (stream.eol()) state.javaScriptLine = false;
119 return tok || true;
120 }
121 }
122 function javaScriptArguments(stream, state) {
123 if (state.javaScriptArguments) {
124 if (state.javaScriptArgumentsDepth === 0 && stream.peek() !== '(') {
125 state.javaScriptArguments = false;
126 return;
127 }
128 if (stream.peek() === '(') {
129 state.javaScriptArgumentsDepth++;
130 } else if (stream.peek() === ')') {
131 state.javaScriptArgumentsDepth--;
132 }
133 if (state.javaScriptArgumentsDepth === 0) {
134 state.javaScriptArguments = false;
135 return;
136 }
137
138 var tok = jsMode.token(stream, state.jsState);
139 return tok || true;
140 }
141 }
142
143 function yieldStatement(stream) {
144 if (stream.match(/^yield\b/)) {
145 return 'keyword';
146 }
147 }
148
149 function doctype(stream) {
150 if (stream.match(/^(?:doctype) *([^\n]+)?/)) {
151 return DOCTYPE;
152 }
153 }
154
155 function interpolation(stream, state) {
156 if (stream.match('#{')) {
157 state.isInterpolating = true;
158 state.interpolationNesting = 0;
159 return 'punctuation';
160 }
161 }
162
163 function interpolationContinued(stream, state) {
164 if (state.isInterpolating) {
165 if (stream.peek() === '}') {
166 state.interpolationNesting--;
167 if (state.interpolationNesting < 0) {
168 stream.next();
169 state.isInterpolating = false;
170 return 'punctuation';
171 }
172 } else if (stream.peek() === '{') {
173 state.interpolationNesting++;
174 }
175 return jsMode.token(stream, state.jsState) || true;
176 }
177 }
178
179 function caseStatement(stream, state) {
180 if (stream.match(/^case\b/)) {
181 state.javaScriptLine = true;
182 return KEYWORD;
183 }
184 }
185
186 function when(stream, state) {
187 if (stream.match(/^when\b/)) {
188 state.javaScriptLine = true;
189 state.javaScriptLineExcludesColon = true;
190 return KEYWORD;
191 }
192 }
193
194 function defaultStatement(stream) {
195 if (stream.match(/^default\b/)) {
196 return KEYWORD;
197 }
198 }
199
200 function extendsStatement(stream, state) {
201 if (stream.match(/^extends?\b/)) {
202 state.restOfLine = 'string';
203 return KEYWORD;
204 }
205 }
206
207 function append(stream, state) {
208 if (stream.match(/^append\b/)) {
209 state.restOfLine = 'variable';
210 return KEYWORD;
211 }
212 }
213 function prepend(stream, state) {
214 if (stream.match(/^prepend\b/)) {
215 state.restOfLine = 'variable';
216 return KEYWORD;
217 }
218 }
219 function block(stream, state) {
220 if (stream.match(/^block\b *(?:(prepend|append)\b)?/)) {
221 state.restOfLine = 'variable';
222 return KEYWORD;
223 }
224 }
225
226 function include(stream, state) {
227 if (stream.match(/^include\b/)) {
228 state.restOfLine = 'string';
229 return KEYWORD;
230 }
231 }
232
233 function includeFiltered(stream, state) {
234 if (stream.match(/^include:([a-zA-Z0-9\-]+)/, false) && stream.match('include')) {
235 state.isIncludeFiltered = true;
236 return KEYWORD;
237 }
238 }
239
240 function includeFilteredContinued(stream, state) {
241 if (state.isIncludeFiltered) {
242 var tok = filter(stream, state);
243 state.isIncludeFiltered = false;
244 state.restOfLine = 'string';
245 return tok;
246 }
247 }
248
249 function mixin(stream, state) {
250 if (stream.match(/^mixin\b/)) {
251 state.javaScriptLine = true;
252 return KEYWORD;
253 }
254 }
255
256 function call(stream, state) {
257 if (stream.match(/^\+([-\w]+)/)) {
258 if (!stream.match(/^\( *[-\w]+ *=/, false)) {
259 state.javaScriptArguments = true;
260 state.javaScriptArgumentsDepth = 0;
261 }
262 return 'variable';
263 }
264 if (stream.match(/^\+#{/, false)) {
265 stream.next();
266 state.mixinCallAfter = true;
267 return interpolation(stream, state);
268 }
269 }
270 function callArguments(stream, state) {
271 if (state.mixinCallAfter) {
272 state.mixinCallAfter = false;
273 if (!stream.match(/^\( *[-\w]+ *=/, false)) {
274 state.javaScriptArguments = true;
275 state.javaScriptArgumentsDepth = 0;
276 }
277 return true;
278 }
279 }
280
281 function conditional(stream, state) {
282 if (stream.match(/^(if|unless|else if|else)\b/)) {
283 state.javaScriptLine = true;
284 return KEYWORD;
285 }
286 }
287
288 function each(stream, state) {
289 if (stream.match(/^(- *)?(each|for)\b/)) {
290 state.isEach = true;
291 return KEYWORD;
292 }
293 }
294 function eachContinued(stream, state) {
295 if (state.isEach) {
296 if (stream.match(/^ in\b/)) {
297 state.javaScriptLine = true;
298 state.isEach = false;
299 return KEYWORD;
300 } else if (stream.sol() || stream.eol()) {
301 state.isEach = false;
302 } else if (stream.next()) {
303 while (!stream.match(/^ in\b/, false) && stream.next());
304 return 'variable';
305 }
306 }
307 }
308
309 function whileStatement(stream, state) {
310 if (stream.match(/^while\b/)) {
311 state.javaScriptLine = true;
312 return KEYWORD;
313 }
314 }
315
316 function tag(stream, state) {
317 var captures;
318 if (captures = stream.match(/^(\w(?:[-:\w]*\w)?)\/?/)) {
319 state.lastTag = captures[1].toLowerCase();
320 if (state.lastTag === 'script') {
321 state.scriptType = 'application/javascript';
322 }
323 return 'tag';
324 }
325 }
326
327 function filter(stream, state) {
328 if (stream.match(/^:([\w\-]+)/)) {
329 var innerMode;
330 if (config && config.innerModes) {
331 innerMode = config.innerModes(stream.current().substring(1));
332 }
333 if (!innerMode) {
334 innerMode = stream.current().substring(1);
335 }
336 if (typeof innerMode === 'string') {
337 innerMode = CodeMirror.getMode(config, innerMode);
338 }
339 setInnerMode(stream, state, innerMode);
340 return 'atom';
341 }
342 }
343
344 function code(stream, state) {
345 if (stream.match(/^(!?=|-)/)) {
346 state.javaScriptLine = true;
347 return 'punctuation';
348 }
349 }
350
351 function id(stream) {
352 if (stream.match(/^#([\w-]+)/)) {
353 return ID;
354 }
355 }
356
357 function className(stream) {
358 if (stream.match(/^\.([\w-]+)/)) {
359 return CLASS;
360 }
361 }
362
363 function attrs(stream, state) {
364 if (stream.peek() == '(') {
365 stream.next();
366 state.isAttrs = true;
367 state.attrsNest = [];
368 state.inAttributeName = true;
369 state.attrValue = '';
370 state.attributeIsType = false;
371 return 'punctuation';
372 }
373 }
374
375 function attrsContinued(stream, state) {
376 if (state.isAttrs) {
377 if (ATTRS_NEST[stream.peek()]) {
378 state.attrsNest.push(ATTRS_NEST[stream.peek()]);
379 }
380 if (state.attrsNest[state.attrsNest.length - 1] === stream.peek()) {
381 state.attrsNest.pop();
382 } else if (stream.eat(')')) {
383 state.isAttrs = false;
384 return 'punctuation';
385 }
386 if (state.inAttributeName && stream.match(/^[^=,\)!]+/)) {
387 if (stream.peek() === '=' || stream.peek() === '!') {
388 state.inAttributeName = false;
389 state.jsState = CodeMirror.startState(jsMode);
390 if (state.lastTag === 'script' && stream.current().trim().toLowerCase() === 'type') {
391 state.attributeIsType = true;
392 } else {
393 state.attributeIsType = false;
394 }
395 }
396 return 'attribute';
397 }
398
399 var tok = jsMode.token(stream, state.jsState);
400 if (state.attributeIsType && tok === 'string') {
401 state.scriptType = stream.current().toString();
402 }
403 if (state.attrsNest.length === 0 && (tok === 'string' || tok === 'variable' || tok === 'keyword')) {
404 try {
405 Function('', 'var x ' + state.attrValue.replace(/,\s*$/, '').replace(/^!/, ''));
406 state.inAttributeName = true;
407 state.attrValue = '';
408 stream.backUp(stream.current().length);
409 return attrsContinued(stream, state);
410 } catch (ex) {
411 //not the end of an attribute
412 }
413 }
414 state.attrValue += stream.current();
415 return tok || true;
416 }
417 }
418
419 function attributesBlock(stream, state) {
420 if (stream.match(/^&attributes\b/)) {
421 state.javaScriptArguments = true;
422 state.javaScriptArgumentsDepth = 0;
423 return 'keyword';
424 }
425 }
426
427 function indent(stream) {
428 if (stream.sol() && stream.eatSpace()) {
429 return 'indent';
430 }
431 }
432
433 function comment(stream, state) {
434 if (stream.match(/^ *\/\/(-)?([^\n]*)/)) {
435 state.indentOf = stream.indentation();
436 state.indentToken = 'comment';
437 return 'comment';
438 }
439 }
440
441 function colon(stream) {
442 if (stream.match(/^: */)) {
443 return 'colon';
444 }
445 }
446
447 function text(stream, state) {
448 if (stream.match(/^(?:\| ?| )([^\n]+)/)) {
449 return 'string';
450 }
451 if (stream.match(/^(<[^\n]*)/, false)) {
452 // html string
453 setInnerMode(stream, state, 'htmlmixed');
454 state.innerModeForLine = true;
455 return innerMode(stream, state, true);
456 }
457 }
458
459 function dot(stream, state) {
460 if (stream.eat('.')) {
461 var innerMode = null;
462 if (state.lastTag === 'script' && state.scriptType.toLowerCase().indexOf('javascript') != -1) {
463 innerMode = state.scriptType.toLowerCase().replace(/"|'/g, '');
464 } else if (state.lastTag === 'style') {
465 innerMode = 'css';
466 }
467 setInnerMode(stream, state, innerMode);
468 return 'dot';
469 }
470 }
471
472 function fail(stream) {
473 stream.next();
474 return null;
475 }
476
477
478 function setInnerMode(stream, state, mode) {
479 mode = CodeMirror.mimeModes[mode] || mode;
480 mode = config.innerModes ? config.innerModes(mode) || mode : mode;
481 mode = CodeMirror.mimeModes[mode] || mode;
482 mode = CodeMirror.getMode(config, mode);
483 state.indentOf = stream.indentation();
484
485 if (mode && mode.name !== 'null') {
486 state.innerMode = mode;
487 } else {
488 state.indentToken = 'string';
489 }
490 }
491 function innerMode(stream, state, force) {
492 if (stream.indentation() > state.indentOf || (state.innerModeForLine && !stream.sol()) || force) {
493 if (state.innerMode) {
494 if (!state.innerState) {
495 state.innerState = state.innerMode.startState ? CodeMirror.startState(state.innerMode, stream.indentation()) : {};
496 }
497 return stream.hideFirstChars(state.indentOf + 2, function () {
498 return state.innerMode.token(stream, state.innerState) || true;
499 });
500 } else {
501 stream.skipToEnd();
502 return state.indentToken;
503 }
504 } else if (stream.sol()) {
505 state.indentOf = Infinity;
506 state.indentToken = null;
507 state.innerMode = null;
508 state.innerState = null;
509 }
510 }
511 function restOfLine(stream, state) {
512 if (stream.sol()) {
513 // if restOfLine was set at end of line, ignore it
514 state.restOfLine = '';
515 }
516 if (state.restOfLine) {
517 stream.skipToEnd();
518 var tok = state.restOfLine;
519 state.restOfLine = '';
520 return tok;
521 }
522 }
523
524
525 function startState() {
526 return new State();
527 }
528 function copyState(state) {
529 return state.copy();
530 }
531 /**
532 * Get the next token in the stream
533 *
534 * @param {Stream} stream
535 * @param {State} state
536 */
537 function nextToken(stream, state) {
538 var tok = innerMode(stream, state)
539 || restOfLine(stream, state)
540 || interpolationContinued(stream, state)
541 || includeFilteredContinued(stream, state)
542 || eachContinued(stream, state)
543 || attrsContinued(stream, state)
544 || javaScript(stream, state)
545 || javaScriptArguments(stream, state)
546 || callArguments(stream, state)
547
548 || yieldStatement(stream)
549 || doctype(stream)
550 || interpolation(stream, state)
551 || caseStatement(stream, state)
552 || when(stream, state)
553 || defaultStatement(stream)
554 || extendsStatement(stream, state)
555 || append(stream, state)
556 || prepend(stream, state)
557 || block(stream, state)
558 || include(stream, state)
559 || includeFiltered(stream, state)
560 || mixin(stream, state)
561 || call(stream, state)
562 || conditional(stream, state)
563 || each(stream, state)
564 || whileStatement(stream, state)
565 || tag(stream, state)
566 || filter(stream, state)
567 || code(stream, state)
568 || id(stream)
569 || className(stream)
570 || attrs(stream, state)
571 || attributesBlock(stream, state)
572 || indent(stream)
573 || text(stream, state)
574 || comment(stream, state)
575 || colon(stream)
576 || dot(stream, state)
577 || fail(stream);
578
579 return tok === true ? null : tok;
580 }
581 return {
582 startState: startState,
583 copyState: copyState,
584 token: nextToken
585 };
586 }, 'javascript', 'css', 'htmlmixed');
587
588 CodeMirror.defineMIME('text/x-pug', 'pug');
589 CodeMirror.defineMIME('text/x-jade', 'pug');
590
591 });
@@ -0,0 +1,303 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4
5 // SAS mode copyright (c) 2016 Jared Dean, SAS Institute
6 // Created by Jared Dean
7
8 // TODO
9 // indent and de-indent
10 // identify macro variables
11
12
13 //Definitions
14 // comment -- text within * ; or /* */
15 // keyword -- SAS language variable
16 // variable -- macro variables starts with '&' or variable formats
17 // variable-2 -- DATA Step, proc, or macro names
18 // string -- text within ' ' or " "
19 // operator -- numeric operator + / - * ** le eq ge ... and so on
20 // builtin -- proc %macro data run mend
21 // atom
22 // def
23
24 (function(mod) {
25 if (typeof exports == "object" && typeof module == "object") // CommonJS
26 mod(require("../../lib/codemirror"));
27 else if (typeof define == "function" && define.amd) // AMD
28 define(["../../lib/codemirror"], mod);
29 else // Plain browser env
30 mod(CodeMirror);
31 })(function(CodeMirror) {
32 "use strict";
33
34 CodeMirror.defineMode("sas", function () {
35 var words = {};
36 var isDoubleOperatorSym = {
37 eq: 'operator',
38 lt: 'operator',
39 le: 'operator',
40 gt: 'operator',
41 ge: 'operator',
42 "in": 'operator',
43 ne: 'operator',
44 or: 'operator'
45 };
46 var isDoubleOperatorChar = /(<=|>=|!=|<>)/;
47 var isSingleOperatorChar = /[=\(:\),{}.*<>+\-\/^\[\]]/;
48
49 // Takes a string of words separated by spaces and adds them as
50 // keys with the value of the first argument 'style'
51 function define(style, string, context) {
52 if (context) {
53 var split = string.split(' ');
54 for (var i = 0; i < split.length; i++) {
55 words[split[i]] = {style: style, state: context};
56 }
57 }
58 }
59 //datastep
60 define('def', 'stack pgm view source debug nesting nolist', ['inDataStep']);
61 define('def', 'if while until for do do; end end; then else cancel', ['inDataStep']);
62 define('def', 'label format _n_ _error_', ['inDataStep']);
63 define('def', 'ALTER BUFNO BUFSIZE CNTLLEV COMPRESS DLDMGACTION ENCRYPT ENCRYPTKEY EXTENDOBSCOUNTER GENMAX GENNUM INDEX LABEL OBSBUF OUTREP PW PWREQ READ REPEMPTY REPLACE REUSE ROLE SORTEDBY SPILL TOBSNO TYPE WRITE FILECLOSE FIRSTOBS IN OBS POINTOBS WHERE WHEREUP IDXNAME IDXWHERE DROP KEEP RENAME', ['inDataStep']);
64 define('def', 'filevar finfo finv fipname fipnamel fipstate first firstobs floor', ['inDataStep']);
65 define('def', 'varfmt varinfmt varlabel varlen varname varnum varray varrayx vartype verify vformat vformatd vformatdx vformatn vformatnx vformatw vformatwx vformatx vinarray vinarrayx vinformat vinformatd vinformatdx vinformatn vinformatnx vinformatw vinformatwx vinformatx vlabel vlabelx vlength vlengthx vname vnamex vnferr vtype vtypex weekday', ['inDataStep']);
66 define('def', 'zipfips zipname zipnamel zipstate', ['inDataStep']);
67 define('def', 'put putc putn', ['inDataStep']);
68 define('builtin', 'data run', ['inDataStep']);
69
70
71 //proc
72 define('def', 'data', ['inProc']);
73
74 // flow control for macros
75 define('def', '%if %end %end; %else %else; %do %do; %then', ['inMacro']);
76
77 //everywhere
78 define('builtin', 'proc run; quit; libname filename %macro %mend option options', ['ALL']);
79
80 define('def', 'footnote title libname ods', ['ALL']);
81 define('def', '%let %put %global %sysfunc %eval ', ['ALL']);
82 // automatic macro variables http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#a003167023.htm
83 define('variable', '&sysbuffr &syscc &syscharwidth &syscmd &sysdate &sysdate9 &sysday &sysdevic &sysdmg &sysdsn &sysencoding &sysenv &syserr &syserrortext &sysfilrc &syshostname &sysindex &sysinfo &sysjobid &syslast &syslckrc &syslibrc &syslogapplname &sysmacroname &sysmenv &sysmsg &sysncpu &sysodspath &sysparm &syspbuff &sysprocessid &sysprocessname &sysprocname &sysrc &sysscp &sysscpl &sysscpl &syssite &sysstartid &sysstartname &systcpiphostname &systime &sysuserid &sysver &sysvlong &sysvlong4 &syswarningtext', ['ALL']);
84
85 //footnote[1-9]? title[1-9]?
86
87 //options statement
88 define('def', 'source2 nosource2 page pageno pagesize', ['ALL']);
89
90 //proc and datastep
91 define('def', '_all_ _character_ _cmd_ _freq_ _i_ _infile_ _last_ _msg_ _null_ _numeric_ _temporary_ _type_ abort abs addr adjrsq airy alpha alter altlog altprint and arcos array arsin as atan attrc attrib attrn authserver autoexec awscontrol awsdef awsmenu awsmenumerge awstitle backward band base betainv between blocksize blshift bnot bor brshift bufno bufsize bxor by byerr byline byte calculated call cards cards4 catcache cbufno cdf ceil center cexist change chisq cinv class cleanup close cnonct cntllev coalesce codegen col collate collin column comamid comaux1 comaux2 comdef compbl compound compress config continue convert cos cosh cpuid create cross crosstab css curobs cv daccdb daccdbsl daccsl daccsyd dacctab dairy datalines datalines4 datejul datepart datetime day dbcslang dbcstype dclose ddm delete delimiter depdb depdbsl depsl depsyd deptab dequote descending descript design= device dflang dhms dif digamma dim dinfo display distinct dkricond dkrocond dlm dnum do dopen doptname doptnum dread drop dropnote dsname dsnferr echo else emaildlg emailid emailpw emailserver emailsys encrypt end endsas engine eof eov erf erfc error errorcheck errors exist exp fappend fclose fcol fdelete feedback fetch fetchobs fexist fget file fileclose fileexist filefmt filename fileref fmterr fmtsearch fnonct fnote font fontalias fopen foptname foptnum force formatted formchar formdelim formdlim forward fpoint fpos fput fread frewind frlen from fsep fuzz fwrite gaminv gamma getoption getvarc getvarn go goto group gwindow hbar hbound helpenv helploc hms honorappearance hosthelp hostprint hour hpct html hvar ibessel ibr id if index indexc indexw initcmd initstmt inner input inputc inputn inr insert int intck intnx into intrr invaliddata irr is jbessel join juldate keep kentb kurtosis label lag last lbound leave left length levels lgamma lib library libref line linesize link list log log10 log2 logpdf logpmf logsdf lostcard lowcase lrecl ls macro macrogen maps mautosource max maxdec maxr mdy mean measures median memtype merge merror min minute missing missover mlogic mod mode model modify month mopen mort mprint mrecall msglevel msymtabmax mvarsize myy n nest netpv new news nmiss no nobatch nobs nocaps nocardimage nocenter nocharcode nocmdmac nocol nocum nodate nodbcs nodetails nodmr nodms nodmsbatch nodup nodupkey noduplicates noechoauto noequals noerrorabend noexitwindows nofullstimer noicon noimplmac noint nolist noloadlist nomiss nomlogic nomprint nomrecall nomsgcase nomstored nomultenvappl nonotes nonumber noobs noovp nopad nopercent noprint noprintinit normal norow norsasuser nosetinit nosplash nosymbolgen note notes notitle notitles notsorted noverbose noxsync noxwait npv null number numkeys nummousekeys nway obs on open order ordinal otherwise out outer outp= output over ovp p(1 5 10 25 50 75 90 95 99) pad pad2 paired parm parmcards path pathdll pathname pdf peek peekc pfkey pmf point poisson poke position printer probbeta probbnml probchi probf probgam probhypr probit probnegb probnorm probsig probt procleave prt ps pw pwreq qtr quote r ranbin rancau ranexp rangam range ranks rannor ranpoi rantbl rantri ranuni read recfm register regr remote remove rename repeat replace resolve retain return reuse reverse rewind right round rsquare rtf rtrace rtraceloc s s2 samploc sasautos sascontrol sasfrscr sasmsg sasmstore sasscript sasuser saving scan sdf second select selection separated seq serror set setcomm setot sign simple sin sinh siteinfo skewness skip sle sls sortedby sortpgm sortseq sortsize soundex spedis splashlocation split spool sqrt start std stderr stdin stfips stimer stname stnamel stop stopover subgroup subpopn substr sum sumwgt symbol symbolgen symget symput sysget sysin sysleave sysmsg sysparm sysprint sysprintfont sysprod sysrc system t table tables tan tanh tapeclose tbufsize terminal test then timepart tinv tnonct to today tol tooldef totper transformout translate trantab tranwrd trigamma trim trimn trunc truncover type unformatted uniform union until upcase update user usericon uss validate value var weight when where while wincharset window work workinit workterm write wsum xsync xwait yearcutoff yes yyq min max', ['inDataStep', 'inProc']);
92 define('operator', 'and not ', ['inDataStep', 'inProc']);
93
94 // Main function
95 function tokenize(stream, state) {
96 // Finally advance the stream
97 var ch = stream.next();
98
99 // BLOCKCOMMENT
100 if (ch === '/' && stream.eat('*')) {
101 state.continueComment = true;
102 return "comment";
103 } else if (state.continueComment === true) { // in comment block
104 //comment ends at the beginning of the line
105 if (ch === '*' && stream.peek() === '/') {
106 stream.next();
107 state.continueComment = false;
108 } else if (stream.skipTo('*')) { //comment is potentially later in line
109 stream.skipTo('*');
110 stream.next();
111 if (stream.eat('/'))
112 state.continueComment = false;
113 } else {
114 stream.skipToEnd();
115 }
116 return "comment";
117 }
118
119 if (ch == "*" && stream.column() == stream.indentation()) {
120 stream.skipToEnd()
121 return "comment"
122 }
123
124 // DoubleOperator match
125 var doubleOperator = ch + stream.peek();
126
127 if ((ch === '"' || ch === "'") && !state.continueString) {
128 state.continueString = ch
129 return "string"
130 } else if (state.continueString) {
131 if (state.continueString == ch) {
132 state.continueString = null;
133 } else if (stream.skipTo(state.continueString)) {
134 // quote found on this line
135 stream.next();
136 state.continueString = null;
137 } else {
138 stream.skipToEnd();
139 }
140 return "string";
141 } else if (state.continueString !== null && stream.eol()) {
142 stream.skipTo(state.continueString) || stream.skipToEnd();
143 return "string";
144 } else if (/[\d\.]/.test(ch)) { //find numbers
145 if (ch === ".")
146 stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
147 else if (ch === "0")
148 stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
149 else
150 stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
151 return "number";
152 } else if (isDoubleOperatorChar.test(ch + stream.peek())) { // TWO SYMBOL TOKENS
153 stream.next();
154 return "operator";
155 } else if (isDoubleOperatorSym.hasOwnProperty(doubleOperator)) {
156 stream.next();
157 if (stream.peek() === ' ')
158 return isDoubleOperatorSym[doubleOperator.toLowerCase()];
159 } else if (isSingleOperatorChar.test(ch)) { // SINGLE SYMBOL TOKENS
160 return "operator";
161 }
162
163 // Matches one whole word -- even if the word is a character
164 var word;
165 if (stream.match(/[%&;\w]+/, false) != null) {
166 word = ch + stream.match(/[%&;\w]+/, true);
167 if (/&/.test(word)) return 'variable'
168 } else {
169 word = ch;
170 }
171 // the word after DATA PROC or MACRO
172 if (state.nextword) {
173 stream.match(/[\w]+/);
174 // match memname.libname
175 if (stream.peek() === '.') stream.skipTo(' ');
176 state.nextword = false;
177 return 'variable-2';
178 }
179
180 word = word.toLowerCase()
181 // Are we in a DATA Step?
182 if (state.inDataStep) {
183 if (word === 'run;' || stream.match(/run\s;/)) {
184 state.inDataStep = false;
185 return 'builtin';
186 }
187 // variable formats
188 if ((word) && stream.next() === '.') {
189 //either a format or libname.memname
190 if (/\w/.test(stream.peek())) return 'variable-2';
191 else return 'variable';
192 }
193 // do we have a DATA Step keyword
194 if (word && words.hasOwnProperty(word) &&
195 (words[word].state.indexOf("inDataStep") !== -1 ||
196 words[word].state.indexOf("ALL") !== -1)) {
197 //backup to the start of the word
198 if (stream.start < stream.pos)
199 stream.backUp(stream.pos - stream.start);
200 //advance the length of the word and return
201 for (var i = 0; i < word.length; ++i) stream.next();
202 return words[word].style;
203 }
204 }
205 // Are we in an Proc statement?
206 if (state.inProc) {
207 if (word === 'run;' || word === 'quit;') {
208 state.inProc = false;
209 return 'builtin';
210 }
211 // do we have a proc keyword
212 if (word && words.hasOwnProperty(word) &&
213 (words[word].state.indexOf("inProc") !== -1 ||
214 words[word].state.indexOf("ALL") !== -1)) {
215 stream.match(/[\w]+/);
216 return words[word].style;
217 }
218 }
219 // Are we in a Macro statement?
220 if (state.inMacro) {
221 if (word === '%mend') {
222 if (stream.peek() === ';') stream.next();
223 state.inMacro = false;
224 return 'builtin';
225 }
226 if (word && words.hasOwnProperty(word) &&
227 (words[word].state.indexOf("inMacro") !== -1 ||
228 words[word].state.indexOf("ALL") !== -1)) {
229 stream.match(/[\w]+/);
230 return words[word].style;
231 }
232
233 return 'atom';
234 }
235 // Do we have Keywords specific words?
236 if (word && words.hasOwnProperty(word)) {
237 // Negates the initial next()
238 stream.backUp(1);
239 // Actually move the stream
240 stream.match(/[\w]+/);
241 if (word === 'data' && /=/.test(stream.peek()) === false) {
242 state.inDataStep = true;
243 state.nextword = true;
244 return 'builtin';
245 }
246 if (word === 'proc') {
247 state.inProc = true;
248 state.nextword = true;
249 return 'builtin';
250 }
251 if (word === '%macro') {
252 state.inMacro = true;
253 state.nextword = true;
254 return 'builtin';
255 }
256 if (/title[1-9]/.test(word)) return 'def';
257
258 if (word === 'footnote') {
259 stream.eat(/[1-9]/);
260 return 'def';
261 }
262
263 // Returns their value as state in the prior define methods
264 if (state.inDataStep === true && words[word].state.indexOf("inDataStep") !== -1)
265 return words[word].style;
266 if (state.inProc === true && words[word].state.indexOf("inProc") !== -1)
267 return words[word].style;
268 if (state.inMacro === true && words[word].state.indexOf("inMacro") !== -1)
269 return words[word].style;
270 if (words[word].state.indexOf("ALL") !== -1)
271 return words[word].style;
272 return null;
273 }
274 // Unrecognized syntax
275 return null;
276 }
277
278 return {
279 startState: function () {
280 return {
281 inDataStep: false,
282 inProc: false,
283 inMacro: false,
284 nextword: false,
285 continueString: null,
286 continueComment: false
287 };
288 },
289 token: function (stream, state) {
290 // Strip the spaces, but regex will account for them either way
291 if (stream.eatSpace()) return null;
292 // Go through the main process
293 return tokenize(stream, state);
294 },
295
296 blockCommentStart: "/*",
297 blockCommentEnd: "*/"
298 };
299
300 });
301
302 CodeMirror.defineMIME("text/x-sas", "sas");
303 });
@@ -0,0 +1,195 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11 })(function(CodeMirror) {
12 "use strict";
13
14 function wordRegexp(words) {
15 return new RegExp("^((" + words.join(")|(") + "))\\b");
16 };
17
18 var builtinArray = [
19 "Clamp",
20 "Constructor",
21 "EnforceRange",
22 "Exposed",
23 "ImplicitThis",
24 "Global", "PrimaryGlobal",
25 "LegacyArrayClass",
26 "LegacyUnenumerableNamedProperties",
27 "LenientThis",
28 "NamedConstructor",
29 "NewObject",
30 "NoInterfaceObject",
31 "OverrideBuiltins",
32 "PutForwards",
33 "Replaceable",
34 "SameObject",
35 "TreatNonObjectAsNull",
36 "TreatNullAs",
37 "EmptyString",
38 "Unforgeable",
39 "Unscopeable"
40 ];
41 var builtins = wordRegexp(builtinArray);
42
43 var typeArray = [
44 "unsigned", "short", "long", // UnsignedIntegerType
45 "unrestricted", "float", "double", // UnrestrictedFloatType
46 "boolean", "byte", "octet", // Rest of PrimitiveType
47 "Promise", // PromiseType
48 "ArrayBuffer", "DataView", "Int8Array", "Int16Array", "Int32Array",
49 "Uint8Array", "Uint16Array", "Uint32Array", "Uint8ClampedArray",
50 "Float32Array", "Float64Array", // BufferRelatedType
51 "ByteString", "DOMString", "USVString", "sequence", "object", "RegExp",
52 "Error", "DOMException", "FrozenArray", // Rest of NonAnyType
53 "any", // Rest of SingleType
54 "void" // Rest of ReturnType
55 ];
56 var types = wordRegexp(typeArray);
57
58 var keywordArray = [
59 "attribute", "callback", "const", "deleter", "dictionary", "enum", "getter",
60 "implements", "inherit", "interface", "iterable", "legacycaller", "maplike",
61 "partial", "required", "serializer", "setlike", "setter", "static",
62 "stringifier", "typedef", // ArgumentNameKeyword except
63 // "unrestricted"
64 "optional", "readonly", "or"
65 ];
66 var keywords = wordRegexp(keywordArray);
67
68 var atomArray = [
69 "true", "false", // BooleanLiteral
70 "Infinity", "NaN", // FloatLiteral
71 "null" // Rest of ConstValue
72 ];
73 var atoms = wordRegexp(atomArray);
74
75 CodeMirror.registerHelper("hintWords", "webidl",
76 builtinArray.concat(typeArray).concat(keywordArray).concat(atomArray));
77
78 var startDefArray = ["callback", "dictionary", "enum", "interface"];
79 var startDefs = wordRegexp(startDefArray);
80
81 var endDefArray = ["typedef"];
82 var endDefs = wordRegexp(endDefArray);
83
84 var singleOperators = /^[:<=>?]/;
85 var integers = /^-?([1-9][0-9]*|0[Xx][0-9A-Fa-f]+|0[0-7]*)/;
86 var floats = /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)/;
87 var identifiers = /^_?[A-Za-z][0-9A-Z_a-z-]*/;
88 var identifiersEnd = /^_?[A-Za-z][0-9A-Z_a-z-]*(?=\s*;)/;
89 var strings = /^"[^"]*"/;
90 var multilineComments = /^\/\*.*?\*\//;
91 var multilineCommentsStart = /^\/\*.*/;
92 var multilineCommentsEnd = /^.*?\*\//;
93
94 function readToken(stream, state) {
95 // whitespace
96 if (stream.eatSpace()) return null;
97
98 // comment
99 if (state.inComment) {
100 if (stream.match(multilineCommentsEnd)) {
101 state.inComment = false;
102 return "comment";
103 }
104 stream.skipToEnd();
105 return "comment";
106 }
107 if (stream.match("//")) {
108 stream.skipToEnd();
109 return "comment";
110 }
111 if (stream.match(multilineComments)) return "comment";
112 if (stream.match(multilineCommentsStart)) {
113 state.inComment = true;
114 return "comment";
115 }
116
117 // integer and float
118 if (stream.match(/^-?[0-9\.]/, false)) {
119 if (stream.match(integers) || stream.match(floats)) return "number";
120 }
121
122 // string
123 if (stream.match(strings)) return "string";
124
125 // identifier
126 if (state.startDef && stream.match(identifiers)) return "def";
127
128 if (state.endDef && stream.match(identifiersEnd)) {
129 state.endDef = false;
130 return "def";
131 }
132
133 if (stream.match(keywords)) return "keyword";
134
135 if (stream.match(types)) {
136 var lastToken = state.lastToken;
137 var nextToken = (stream.match(/^\s*(.+?)\b/, false) || [])[1];
138
139 if (lastToken === ":" || lastToken === "implements" ||
140 nextToken === "implements" || nextToken === "=") {
141 // Used as identifier
142 return "builtin";
143 } else {
144 // Used as type
145 return "variable-3";
146 }
147 }
148
149 if (stream.match(builtins)) return "builtin";
150 if (stream.match(atoms)) return "atom";
151 if (stream.match(identifiers)) return "variable";
152
153 // other
154 if (stream.match(singleOperators)) return "operator";
155
156 // unrecognized
157 stream.next();
158 return null;
159 };
160
161 CodeMirror.defineMode("webidl", function() {
162 return {
163 startState: function() {
164 return {
165 // Is in multiline comment
166 inComment: false,
167 // Last non-whitespace, matched token
168 lastToken: "",
169 // Next token is a definition
170 startDef: false,
171 // Last token of the statement is a definition
172 endDef: false
173 };
174 },
175 token: function(stream, state) {
176 var style = readToken(stream, state);
177
178 if (style) {
179 var cur = stream.current();
180 state.lastToken = cur;
181 if (style === "keyword") {
182 state.startDef = startDefs.test(cur);
183 state.endDef = state.endDef || endDefs.test(cur);
184 } else {
185 state.startDef = false;
186 }
187 }
188
189 return style;
190 }
191 };
192 });
193
194 CodeMirror.defineMIME("text/x-webidl", "webidl");
195 });
@@ -0,0 +1,204 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 // Yacas mode copyright (c) 2015 by Grzegorz Mazur
5 // Loosely based on mathematica mode by Calin Barbat
6
7 (function(mod) {
8 if (typeof exports == "object" && typeof module == "object") // CommonJS
9 mod(require("../../lib/codemirror"));
10 else if (typeof define == "function" && define.amd) // AMD
11 define(["../../lib/codemirror"], mod);
12 else // Plain browser env
13 mod(CodeMirror);
14 })(function(CodeMirror) {
15 "use strict";
16
17 CodeMirror.defineMode('yacas', function(_config, _parserConfig) {
18
19 function words(str) {
20 var obj = {}, words = str.split(" ");
21 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
22 return obj;
23 }
24
25 var bodiedOps = words("Assert BackQuote D Defun Deriv For ForEach FromFile " +
26 "FromString Function Integrate InverseTaylor Limit " +
27 "LocalSymbols Macro MacroRule MacroRulePattern " +
28 "NIntegrate Rule RulePattern Subst TD TExplicitSum " +
29 "TSum Taylor Taylor1 Taylor2 Taylor3 ToFile " +
30 "ToStdout ToString TraceRule Until While");
31
32 // patterns
33 var pFloatForm = "(?:(?:\\.\\d+|\\d+\\.\\d*|\\d+)(?:[eE][+-]?\\d+)?)";
34 var pIdentifier = "(?:[a-zA-Z\\$'][a-zA-Z0-9\\$']*)";
35
36 // regular expressions
37 var reFloatForm = new RegExp(pFloatForm);
38 var reIdentifier = new RegExp(pIdentifier);
39 var rePattern = new RegExp(pIdentifier + "?_" + pIdentifier);
40 var reFunctionLike = new RegExp(pIdentifier + "\\s*\\(");
41
42 function tokenBase(stream, state) {
43 var ch;
44
45 // get next character
46 ch = stream.next();
47
48 // string
49 if (ch === '"') {
50 state.tokenize = tokenString;
51 return state.tokenize(stream, state);
52 }
53
54 // comment
55 if (ch === '/') {
56 if (stream.eat('*')) {
57 state.tokenize = tokenComment;
58 return state.tokenize(stream, state);
59 }
60 if (stream.eat("/")) {
61 stream.skipToEnd();
62 return "comment";
63 }
64 }
65
66 // go back one character
67 stream.backUp(1);
68
69 // update scope info
70 var m = stream.match(/^(\w+)\s*\(/, false);
71 if (m !== null && bodiedOps.hasOwnProperty(m[1]))
72 state.scopes.push('bodied');
73
74 var scope = currentScope(state);
75
76 if (scope === 'bodied' && ch === '[')
77 state.scopes.pop();
78
79 if (ch === '[' || ch === '{' || ch === '(')
80 state.scopes.push(ch);
81
82 scope = currentScope(state);
83
84 if (scope === '[' && ch === ']' ||
85 scope === '{' && ch === '}' ||
86 scope === '(' && ch === ')')
87 state.scopes.pop();
88
89 if (ch === ';') {
90 while (scope === 'bodied') {
91 state.scopes.pop();
92 scope = currentScope(state);
93 }
94 }
95
96 // look for ordered rules
97 if (stream.match(/\d+ *#/, true, false)) {
98 return 'qualifier';
99 }
100
101 // look for numbers
102 if (stream.match(reFloatForm, true, false)) {
103 return 'number';
104 }
105
106 // look for placeholders
107 if (stream.match(rePattern, true, false)) {
108 return 'variable-3';
109 }
110
111 // match all braces separately
112 if (stream.match(/(?:\[|\]|{|}|\(|\))/, true, false)) {
113 return 'bracket';
114 }
115
116 // literals looking like function calls
117 if (stream.match(reFunctionLike, true, false)) {
118 stream.backUp(1);
119 return 'variable';
120 }
121
122 // all other identifiers
123 if (stream.match(reIdentifier, true, false)) {
124 return 'variable-2';
125 }
126
127 // operators; note that operators like @@ or /; are matched separately for each symbol.
128 if (stream.match(/(?:\\|\+|\-|\*|\/|,|;|\.|:|@|~|=|>|<|&|\||_|`|'|\^|\?|!|%|#)/, true, false)) {
129 return 'operator';
130 }
131
132 // everything else is an error
133 return 'error';
134 }
135
136 function tokenString(stream, state) {
137 var next, end = false, escaped = false;
138 while ((next = stream.next()) != null) {
139 if (next === '"' && !escaped) {
140 end = true;
141 break;
142 }
143 escaped = !escaped && next === '\\';
144 }
145 if (end && !escaped) {
146 state.tokenize = tokenBase;
147 }
148 return 'string';
149 };
150
151 function tokenComment(stream, state) {
152 var prev, next;
153 while((next = stream.next()) != null) {
154 if (prev === '*' && next === '/') {
155 state.tokenize = tokenBase;
156 break;
157 }
158 prev = next;
159 }
160 return 'comment';
161 }
162
163 function currentScope(state) {
164 var scope = null;
165 if (state.scopes.length > 0)
166 scope = state.scopes[state.scopes.length - 1];
167 return scope;
168 }
169
170 return {
171 startState: function() {
172 return {
173 tokenize: tokenBase,
174 scopes: []
175 };
176 },
177 token: function(stream, state) {
178 if (stream.eatSpace()) return null;
179 return state.tokenize(stream, state);
180 },
181 indent: function(state, textAfter) {
182 if (state.tokenize !== tokenBase && state.tokenize !== null)
183 return CodeMirror.Pass;
184
185 var delta = 0;
186 if (textAfter === ']' || textAfter === '];' ||
187 textAfter === '}' || textAfter === '};' ||
188 textAfter === ');')
189 delta = -1;
190
191 return (state.scopes.length + delta) * _config.indentUnit;
192 },
193 electricChars: "{}[]();",
194 blockCommentStart: "/*",
195 blockCommentEnd: "*/",
196 lineComment: "//"
197 };
198 });
199
200 CodeMirror.defineMIME('text/x-yacas', {
201 name: 'yacas'
202 });
203
204 });
@@ -5,6 +5,7 b''
5 font-family: monospace;
5 font-family: monospace;
6 height: 300px;
6 height: 300px;
7 color: black;
7 color: black;
8 direction: ltr;
8 border-radius: @border-radius;
9 border-radius: @border-radius;
9 border: @border-thickness solid @grey6;
10 border: @border-thickness solid @grey6;
10 margin: 0 0 @padding;
11 margin: 0 0 @padding;
@@ -15,7 +16,8 b''
15 .CodeMirror-lines {
16 .CodeMirror-lines {
16 padding: 4px 0; /* Vertical padding around content */
17 padding: 4px 0; /* Vertical padding around content */
17 }
18 }
18 .CodeMirror pre {
19 .CodeMirror pre.CodeMirror-line,
20 .CodeMirror pre.CodeMirror-line-like {
19 padding: 0 4px; /* Horizontal padding of content */
21 padding: 0 4px; /* Horizontal padding of content */
20 }
22 }
21
23
@@ -44,28 +46,36 b''
44
46
45 /* CURSOR */
47 /* CURSOR */
46
48
47 .CodeMirror div.CodeMirror-cursor {
49 .CodeMirror-cursor {
48 border-left: 1px solid black;
50 border-left: 1px solid black;
51 border-right: none;
52 width: 0;
49 }
53 }
50 /* Shown when moving in bi-directional text */
54 /* Shown when moving in bi-directional text */
51 .CodeMirror div.CodeMirror-secondarycursor {
55 .CodeMirror div.CodeMirror-secondarycursor {
52 border-left: 1px solid silver;
56 border-left: 1px solid silver;
53 }
57 }
54 .CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
58 .cm-fat-cursor .CodeMirror-cursor {
55 width: auto;
59 width: auto;
56 border: 0;
60 border: 0 !important;
57 background: @grey6;
61 background: @grey6;
58 }
62 }
59 .CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
63 .cm-fat-cursor div.CodeMirror-cursors {
60 z-index: 1;
64 z-index: 1;
61 }
65 }
62
66 .cm-fat-cursor-mark {
67 background-color: rgba(20, 255, 20, 0.5);
68 -webkit-animation: blink 1.06s steps(1) infinite;
69 -moz-animation: blink 1.06s steps(1) infinite;
70 animation: blink 1.06s steps(1) infinite;
71 }
63 .cm-animate-fat-cursor {
72 .cm-animate-fat-cursor {
64 width: auto;
73 width: auto;
65 border: 0;
74 border: 0;
66 -webkit-animation: blink 1.06s steps(1) infinite;
75 -webkit-animation: blink 1.06s steps(1) infinite;
67 -moz-animation: blink 1.06s steps(1) infinite;
76 -moz-animation: blink 1.06s steps(1) infinite;
68 animation: blink 1.06s steps(1) infinite;
77 animation: blink 1.06s steps(1) infinite;
78 background-color: #7e7;
69 }
79 }
70 @-moz-keyframes blink {
80 @-moz-keyframes blink {
71 0% { background: #7e7; }
81 0% { background: #7e7; }
@@ -84,12 +94,18 b''
84 }
94 }
85
95
86 /* Can style cursor different in overwrite (non-insert) mode */
96 /* Can style cursor different in overwrite (non-insert) mode */
87 div.CodeMirror-overwrite div.CodeMirror-cursor {}
97 .CodeMirror-overwrite .CodeMirror-cursor {}
88
98
89 .cm-tab { display: inline-block; text-decoration: inherit; }
99 .cm-tab { display: inline-block; text-decoration: inherit; }
90
100
101 .CodeMirror-rulers {
102 position: absolute;
103 left: 0; right: 0; top: -50px; bottom: 0;
104 overflow: hidden;
105 }
91 .CodeMirror-ruler {
106 .CodeMirror-ruler {
92 border-left: 1px solid #ccc;
107 border-left: 1px solid #ccc;
108 top: 0; bottom: 0;
93 position: absolute;
109 position: absolute;
94 }
110 }
95
111
@@ -113,7 +129,7 b' div.CodeMirror-overwrite div.CodeMirror-'
113 .cm-s-default .cm-property,
129 .cm-s-default .cm-property,
114 .cm-s-default .cm-operator {}
130 .cm-s-default .cm-operator {}
115 .cm-s-default .cm-variable-2 {color: #05a;}
131 .cm-s-default .cm-variable-2 {color: #05a;}
116 .cm-s-default .cm-variable-3 {color: #085;}
132 .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
117 .cm-s-default .cm-comment {color: #a50;}
133 .cm-s-default .cm-comment {color: #a50;}
118 .cm-s-default .cm-string {color: #a11;}
134 .cm-s-default .cm-string {color: #a11;}
119 .cm-s-default .cm-string-2 {color: #f50;}
135 .cm-s-default .cm-string-2 {color: #f50;}
@@ -133,8 +149,8 b' div.CodeMirror-overwrite div.CodeMirror-'
133
149
134 /* Default styles for common addons */
150 /* Default styles for common addons */
135
151
136 div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
152 div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
137 div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
153 div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
138 .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
154 .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
139 .CodeMirror-activeline-background {background: #e8f2ff;}
155 .CodeMirror-activeline-background {background: #e8f2ff;}
140
156
@@ -191,20 +207,21 b' div.CodeMirror span.CodeMirror-nonmatchi'
191
207
192 .CodeMirror-gutters {
208 .CodeMirror-gutters {
193 position: absolute; left: 0; top: 0;
209 position: absolute; left: 0; top: 0;
210 min-height: 100%;
194 z-index: 3;
211 z-index: 3;
195 }
212 }
196 .CodeMirror-gutter {
213 .CodeMirror-gutter {
197 white-space: normal;
214 white-space: normal;
198 height: 100%;
215 height: 100%;
199 display: inline-block;
216 display: inline-block;
217 vertical-align: top;
200 margin-bottom: -30px;
218 margin-bottom: -30px;
201 /* Hack to make IE7 behave */
202 *zoom:1;
203 *display:inline;
204 }
219 }
205 .CodeMirror-gutter-wrapper {
220 .CodeMirror-gutter-wrapper {
206 position: absolute;
221 position: absolute;
207 z-index: 4;
222 z-index: 4;
223 background: none !important;
224 border: none !important;
208 height: 100%;
225 height: 100%;
209 }
226 }
210 .CodeMirror-gutter-background {
227 .CodeMirror-gutter-background {
@@ -227,7 +244,8 b' div.CodeMirror span.CodeMirror-nonmatchi'
227 cursor: text;
244 cursor: text;
228 min-height: 1px; /* prevents collapsing before first draw */
245 min-height: 1px; /* prevents collapsing before first draw */
229 }
246 }
230 .CodeMirror pre {
247 .CodeMirror pre.CodeMirror-line,
248 .CodeMirror pre.CodeMirror-line-like {
231 /* Reset some styles that the rest of the page might have set */
249 /* Reset some styles that the rest of the page might have set */
232 -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
250 -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
233 border-width: 0;
251 border-width: 0;
@@ -243,8 +261,11 b' div.CodeMirror span.CodeMirror-nonmatchi'
243 position: relative;
261 position: relative;
244 overflow: visible;
262 overflow: visible;
245 -webkit-tap-highlight-color: transparent;
263 -webkit-tap-highlight-color: transparent;
264 -webkit-font-variant-ligatures: contextual;
265 font-variant-ligatures: contextual;
246 }
266 }
247 .CodeMirror-wrap pre {
267 .CodeMirror-wrap pre.CodeMirror-line,
268 .CodeMirror-wrap pre.CodeMirror-line-like {
248 word-wrap: break-word;
269 word-wrap: break-word;
249 white-space: pre-wrap;
270 white-space: pre-wrap;
250 word-break: normal;
271 word-break: normal;
@@ -259,11 +280,14 b' div.CodeMirror span.CodeMirror-nonmatchi'
259 .CodeMirror-linewidget {
280 .CodeMirror-linewidget {
260 position: relative;
281 position: relative;
261 z-index: 2;
282 z-index: 2;
283 padding: 0.1px; /* Force widget margins to stay inside of the container */
262 overflow: auto;
284 overflow: auto;
263 }
285 }
264
286
265 .CodeMirror-widget {}
287 .CodeMirror-widget {}
266
288
289 .CodeMirror-rtl pre { direction: rtl; }
290
267 .CodeMirror-code {
291 .CodeMirror-code {
268 outline: none;
292 outline: none;
269 }
293 }
@@ -286,13 +310,12 b' div.CodeMirror span.CodeMirror-nonmatchi'
286 visibility: hidden;
310 visibility: hidden;
287 }
311 }
288
312
289
313 .CodeMirror-cursor {
290 .CodeMirror div.CodeMirror-cursor {
291 position: absolute;
314 position: absolute;
315 pointer-events: none;
292 border-right: none;
316 border-right: none;
293 width: 0;
317 width: 0;
294 }
318 }
295
296 .CodeMirror-measure pre { position: static; }
319 .CodeMirror-measure pre { position: static; }
297
320
298 div.CodeMirror-cursors {
321 div.CodeMirror-cursors {
@@ -315,13 +338,10 b' div.CodeMirror-dragcursors {'
315 .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
338 .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
316
339
317 .cm-searching {
340 .cm-searching {
318 background: #ffa;
341 background-color: #ffa;
319 background: rgba(255, 255, 0, .4);
342 background-color: rgba(255, 255, 0, .4);
320 }
343 }
321
344
322 /* IE7 hack to prevent it from returning funny offsetTops on the spans */
323 .CodeMirror span { *vertical-align: text-bottom; }
324
325 /* Used to force a border model for a node */
345 /* Used to force a border model for a node */
326 .cm-force-border { padding-right: .1px; }
346 .cm-force-border { padding-right: .1px; }
327
347
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -68,6 +68,7 b''
68 });
68 });
69
69
70 CodeMirror.defineMIME("application/pgp", "asciiarmor");
70 CodeMirror.defineMIME("application/pgp", "asciiarmor");
71 CodeMirror.defineMIME("application/pgp-encrypted", "asciiarmor");
71 CodeMirror.defineMIME("application/pgp-keys", "asciiarmor");
72 CodeMirror.defineMIME("application/pgp-keys", "asciiarmor");
72 CodeMirror.defineMIME("application/pgp-signature", "asciiarmor");
73 CodeMirror.defineMIME("application/pgp-signature", "asciiarmor");
73 });
74 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /*
4 /*
5 * =====================================================================================
5 * =====================================================================================
@@ -9,7 +9,7 b''
9 * Description: CodeMirror mode for Asterisk dialplan
9 * Description: CodeMirror mode for Asterisk dialplan
10 *
10 *
11 * Created: 05/17/2012 09:20:25 PM
11 * Created: 05/17/2012 09:20:25 PM
12 * Revision: none
12 * Revision: 08/05/2019 AstLinux Project: Support block-comments
13 *
13 *
14 * Author: Stas Kobzar (stas@modulis.ca),
14 * Author: Stas Kobzar (stas@modulis.ca),
15 * Company: Modulis.ca Inc.
15 * Company: Modulis.ca Inc.
@@ -67,7 +67,26 b' CodeMirror.defineMode("asterisk", functi'
67 var cur = '';
67 var cur = '';
68 var ch = stream.next();
68 var ch = stream.next();
69 // comment
69 // comment
70 if (state.blockComment) {
71 if (ch == "-" && stream.match("-;", true)) {
72 state.blockComment = false;
73 } else if (stream.skipTo("--;")) {
74 stream.next();
75 stream.next();
76 stream.next();
77 state.blockComment = false;
78 } else {
79 stream.skipToEnd();
80 }
81 return "comment";
82 }
70 if(ch == ";") {
83 if(ch == ";") {
84 if (stream.match("--", true)) {
85 if (!stream.match("-", false)) { // Except ;--- is not a block comment
86 state.blockComment = true;
87 return "comment";
88 }
89 }
71 stream.skipToEnd();
90 stream.skipToEnd();
72 return "comment";
91 return "comment";
73 }
92 }
@@ -124,6 +143,7 b' CodeMirror.defineMode("asterisk", functi'
124 return {
143 return {
125 startState: function() {
144 startState: function() {
126 return {
145 return {
146 blockComment: false,
127 extenStart: false,
147 extenStart: false,
128 extenSame: false,
148 extenSame: false,
129 extenInclude: false,
149 extenInclude: false,
@@ -187,7 +207,11 b' CodeMirror.defineMode("asterisk", functi'
187 }
207 }
188
208
189 return null;
209 return null;
190 }
210 },
211
212 blockCommentStart: ";--",
213 blockCommentEnd: "--;",
214 lineComment: ";"
191 };
215 };
192 });
216 });
193
217
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Brainfuck mode created by Michael Kaminsky https://github.com/mkaminsky11
4 // Brainfuck mode created by Michael Kaminsky https://github.com/mkaminsky11
5
5
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -11,6 +11,41 b''
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 function Context(indented, column, type, info, align, prev) {
15 this.indented = indented;
16 this.column = column;
17 this.type = type;
18 this.info = info;
19 this.align = align;
20 this.prev = prev;
21 }
22 function pushContext(state, col, type, info) {
23 var indent = state.indented;
24 if (state.context && state.context.type == "statement" && type != "statement")
25 indent = state.context.indented;
26 return state.context = new Context(indent, col, type, info, null, state.context);
27 }
28 function popContext(state) {
29 var t = state.context.type;
30 if (t == ")" || t == "]" || t == "}")
31 state.indented = state.context.indented;
32 return state.context = state.context.prev;
33 }
34
35 function typeBefore(stream, state, pos) {
36 if (state.prevToken == "variable" || state.prevToken == "type") return true;
37 if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true;
38 if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true;
39 }
40
41 function isTopScope(context) {
42 for (;;) {
43 if (!context || context.type == "top") return true;
44 if (context.type == "}" && context.prev.info != "namespace") return false;
45 context = context.prev;
46 }
47 }
48
14 CodeMirror.defineMode("clike", function(config, parserConfig) {
49 CodeMirror.defineMode("clike", function(config, parserConfig) {
15 var indentUnit = config.indentUnit,
50 var indentUnit = config.indentUnit,
16 statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
51 statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
@@ -30,7 +65,10 b' CodeMirror.defineMode("clike", function('
30 numberStart = parserConfig.numberStart || /[\d\.]/,
65 numberStart = parserConfig.numberStart || /[\d\.]/,
31 number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
66 number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
32 isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
67 isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
33 endStatement = parserConfig.endStatement || /^[;:,]$/;
68 isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/,
69 // An optional function that takes a {string} token and returns true if it
70 // should be treated as a builtin.
71 isReservedIdentifier = parserConfig.isReservedIdentifier || false;
34
72
35 var curPunc, isDefKeyword;
73 var curPunc, isDefKeyword;
36
74
@@ -64,12 +102,12 b' CodeMirror.defineMode("clike", function('
64 }
102 }
65 }
103 }
66 if (isOperatorChar.test(ch)) {
104 if (isOperatorChar.test(ch)) {
67 stream.eatWhile(isOperatorChar);
105 while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
68 return "operator";
106 return "operator";
69 }
107 }
70 stream.eatWhile(/[\w\$_\xa1-\uffff]/);
108 stream.eatWhile(isIdentifierChar);
71 if (namespaceSeparator) while (stream.match(namespaceSeparator))
109 if (namespaceSeparator) while (stream.match(namespaceSeparator))
72 stream.eatWhile(/[\w\$_\xa1-\uffff]/);
110 stream.eatWhile(isIdentifierChar);
73
111
74 var cur = stream.current();
112 var cur = stream.current();
75 if (contains(keywords, cur)) {
113 if (contains(keywords, cur)) {
@@ -77,8 +115,9 b' CodeMirror.defineMode("clike", function('
77 if (contains(defKeywords, cur)) isDefKeyword = true;
115 if (contains(defKeywords, cur)) isDefKeyword = true;
78 return "keyword";
116 return "keyword";
79 }
117 }
80 if (contains(types, cur)) return "variable-3";
118 if (contains(types, cur)) return "type";
81 if (contains(builtin, cur)) {
119 if (contains(builtin, cur)
120 || (isReservedIdentifier && isReservedIdentifier(cur))) {
82 if (contains(blockKeywords, cur)) curPunc = "newstatement";
121 if (contains(blockKeywords, cur)) curPunc = "newstatement";
83 return "builtin";
122 return "builtin";
84 }
123 }
@@ -111,40 +150,9 b' CodeMirror.defineMode("clike", function('
111 return "comment";
150 return "comment";
112 }
151 }
113
152
114 function Context(indented, column, type, align, prev) {
153 function maybeEOL(stream, state) {
115 this.indented = indented;
154 if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context))
116 this.column = column;
155 state.typeAtEndOfLine = typeBefore(stream, state, stream.pos)
117 this.type = type;
118 this.align = align;
119 this.prev = prev;
120 }
121 function isStatement(type) {
122 return type == "statement" || type == "switchstatement" || type == "namespace";
123 }
124 function pushContext(state, col, type) {
125 var indent = state.indented;
126 if (state.context && isStatement(state.context.type) && !isStatement(type))
127 indent = state.context.indented;
128 return state.context = new Context(indent, col, type, null, state.context);
129 }
130 function popContext(state) {
131 var t = state.context.type;
132 if (t == ")" || t == "]" || t == "}")
133 state.indented = state.context.indented;
134 return state.context = state.context.prev;
135 }
136
137 function typeBefore(stream, state) {
138 if (state.prevToken == "variable" || state.prevToken == "variable-3") return true;
139 if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, stream.start))) return true;
140 }
141
142 function isTopScope(context) {
143 for (;;) {
144 if (!context || context.type == "top") return true;
145 if (context.type == "}" && context.prev.type != "namespace") return false;
146 context = context.prev;
147 }
148 }
156 }
149
157
150 // Interface
158 // Interface
@@ -153,7 +161,7 b' CodeMirror.defineMode("clike", function('
153 startState: function(basecolumn) {
161 startState: function(basecolumn) {
154 return {
162 return {
155 tokenize: null,
163 tokenize: null,
156 context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
164 context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false),
157 indented: 0,
165 indented: 0,
158 startOfLine: true,
166 startOfLine: true,
159 prevToken: null
167 prevToken: null
@@ -167,36 +175,32 b' CodeMirror.defineMode("clike", function('
167 state.indented = stream.indentation();
175 state.indented = stream.indentation();
168 state.startOfLine = true;
176 state.startOfLine = true;
169 }
177 }
170 if (stream.eatSpace()) return null;
178 if (stream.eatSpace()) { maybeEOL(stream, state); return null; }
171 curPunc = isDefKeyword = null;
179 curPunc = isDefKeyword = null;
172 var style = (state.tokenize || tokenBase)(stream, state);
180 var style = (state.tokenize || tokenBase)(stream, state);
173 if (style == "comment" || style == "meta") return style;
181 if (style == "comment" || style == "meta") return style;
174 if (ctx.align == null) ctx.align = true;
182 if (ctx.align == null) ctx.align = true;
175
183
176 if (endStatement.test(curPunc)) while (isStatement(state.context.type)) popContext(state);
184 if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false)))
185 while (state.context.type == "statement") popContext(state);
177 else if (curPunc == "{") pushContext(state, stream.column(), "}");
186 else if (curPunc == "{") pushContext(state, stream.column(), "}");
178 else if (curPunc == "[") pushContext(state, stream.column(), "]");
187 else if (curPunc == "[") pushContext(state, stream.column(), "]");
179 else if (curPunc == "(") pushContext(state, stream.column(), ")");
188 else if (curPunc == "(") pushContext(state, stream.column(), ")");
180 else if (curPunc == "}") {
189 else if (curPunc == "}") {
181 while (isStatement(ctx.type)) ctx = popContext(state);
190 while (ctx.type == "statement") ctx = popContext(state);
182 if (ctx.type == "}") ctx = popContext(state);
191 if (ctx.type == "}") ctx = popContext(state);
183 while (isStatement(ctx.type)) ctx = popContext(state);
192 while (ctx.type == "statement") ctx = popContext(state);
184 }
193 }
185 else if (curPunc == ctx.type) popContext(state);
194 else if (curPunc == ctx.type) popContext(state);
186 else if (indentStatements &&
195 else if (indentStatements &&
187 (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") ||
196 (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") ||
188 (isStatement(ctx.type) && curPunc == "newstatement"))) {
197 (ctx.type == "statement" && curPunc == "newstatement"))) {
189 var type = "statement";
198 pushContext(state, stream.column(), "statement", stream.current());
190 if (curPunc == "newstatement" && indentSwitch && stream.current() == "switch")
191 type = "switchstatement";
192 else if (style == "keyword" && stream.current() == "namespace")
193 type = "namespace";
194 pushContext(state, stream.column(), type);
195 }
199 }
196
200
197 if (style == "variable" &&
201 if (style == "variable" &&
198 ((state.prevToken == "def" ||
202 ((state.prevToken == "def" ||
199 (parserConfig.typeFirstDefinitions && typeBefore(stream, state) &&
203 (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) &&
200 isTopScope(state.context) && stream.match(/^\s*\(/, false)))))
204 isTopScope(state.context) && stream.match(/^\s*\(/, false)))))
201 style = "def";
205 style = "def";
202
206
@@ -209,24 +213,28 b' CodeMirror.defineMode("clike", function('
209
213
210 state.startOfLine = false;
214 state.startOfLine = false;
211 state.prevToken = isDefKeyword ? "def" : style || curPunc;
215 state.prevToken = isDefKeyword ? "def" : style || curPunc;
216 maybeEOL(stream, state);
212 return style;
217 return style;
213 },
218 },
214
219
215 indent: function(state, textAfter) {
220 indent: function(state, textAfter) {
216 if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
221 if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass;
217 var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
222 var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
218 if (isStatement(ctx.type) && firstChar == "}") ctx = ctx.prev;
223 var closing = firstChar == ctx.type;
224 if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
225 if (parserConfig.dontIndentStatements)
226 while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info))
227 ctx = ctx.prev
219 if (hooks.indent) {
228 if (hooks.indent) {
220 var hook = hooks.indent(state, ctx, textAfter);
229 var hook = hooks.indent(state, ctx, textAfter, indentUnit);
221 if (typeof hook == "number") return hook
230 if (typeof hook == "number") return hook
222 }
231 }
223 var closing = firstChar == ctx.type;
232 var switchBlock = ctx.prev && ctx.prev.info == "switch";
224 var switchBlock = ctx.prev && ctx.prev.type == "switchstatement";
225 if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
233 if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
226 while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
234 while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
227 return ctx.indented
235 return ctx.indented
228 }
236 }
229 if (isStatement(ctx.type))
237 if (ctx.type == "statement")
230 return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
238 return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
231 if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
239 if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
232 return ctx.column + (closing ? 0 : 1);
240 return ctx.column + (closing ? 0 : 1);
@@ -240,6 +248,7 b' CodeMirror.defineMode("clike", function('
240 electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/,
248 electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/,
241 blockCommentStart: "/*",
249 blockCommentStart: "/*",
242 blockCommentEnd: "*/",
250 blockCommentEnd: "*/",
251 blockCommentContinue: " * ",
243 lineComment: "//",
252 lineComment: "//",
244 fold: "brace"
253 fold: "brace"
245 };
254 };
@@ -258,8 +267,52 b' CodeMirror.defineMode("clike", function('
258 }
267 }
259 }
268 }
260 var cKeywords = "auto if break case register continue return default do sizeof " +
269 var cKeywords = "auto if break case register continue return default do sizeof " +
261 "static else struct switch extern typedef union for goto while enum const volatile";
270 "static else struct switch extern typedef union for goto while enum const " +
262 var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t";
271 "volatile inline restrict asm fortran";
272
273 // Keywords from https://en.cppreference.com/w/cpp/keyword includes C++20.
274 var cppKeywords = "alignas alignof and and_eq audit axiom bitand bitor catch " +
275 "class compl concept constexpr const_cast decltype delete dynamic_cast " +
276 "explicit export final friend import module mutable namespace new noexcept " +
277 "not not_eq operator or or_eq override private protected public " +
278 "reinterpret_cast requires static_assert static_cast template this " +
279 "thread_local throw try typeid typename using virtual xor xor_eq";
280
281 var objCKeywords = "bycopy byref in inout oneway out self super atomic nonatomic retain copy " +
282 "readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd " +
283 "@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class " +
284 "@public @package @private @protected @required @optional @try @catch @finally @import " +
285 "@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available";
286
287 var objCBuiltins = "FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION " +
288 " NS_RETURNS_RETAINEDNS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER " +
289 "NS_DESIGNATED_INITIALIZER NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION " +
290 "NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT"
291
292 // Do not use this. Use the cTypes function below. This is global just to avoid
293 // excessive calls when cTypes is being called multiple times during a parse.
294 var basicCTypes = words("int long char short double float unsigned signed " +
295 "void bool");
296
297 // Do not use this. Use the objCTypes function below. This is global just to avoid
298 // excessive calls when objCTypes is being called multiple times during a parse.
299 var basicObjCTypes = words("SEL instancetype id Class Protocol BOOL");
300
301 // Returns true if identifier is a "C" type.
302 // C type is defined as those that are reserved by the compiler (basicTypes),
303 // and those that end in _t (Reserved by POSIX for types)
304 // http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html
305 function cTypes(identifier) {
306 return contains(basicCTypes, identifier) || /.+_t$/.test(identifier);
307 }
308
309 // Returns true if identifier is a "Objective C" type.
310 function objCTypes(identifier) {
311 return cTypes(identifier) || contains(basicObjCTypes, identifier);
312 }
313
314 var cBlockKeywords = "case do else for if switch while struct enum union";
315 var cDefKeywords = "struct enum union";
263
316
264 function cppHook(stream, state) {
317 function cppHook(stream, state) {
265 if (!state.startOfLine) return false
318 if (!state.startOfLine) return false
@@ -277,10 +330,18 b' CodeMirror.defineMode("clike", function('
277 }
330 }
278
331
279 function pointerHook(_stream, state) {
332 function pointerHook(_stream, state) {
280 if (state.prevToken == "variable-3") return "variable-3";
333 if (state.prevToken == "type") return "type";
281 return false;
334 return false;
282 }
335 }
283
336
337 // For C and C++ (and ObjC): identifiers starting with __
338 // or _ followed by a capital letter are reserved for the compiler.
339 function cIsReservedIdentifier(token) {
340 if (!token || token.length < 2) return false;
341 if (token[0] != '_') return false;
342 return (token[1] == '_') || (token[1] !== token[1].toLowerCase());
343 }
344
284 function cpp14Literal(stream) {
345 function cpp14Literal(stream) {
285 stream.eatWhile(/[\w\.']/);
346 stream.eatWhile(/[\w\.']/);
286 return "number";
347 return "number";
@@ -311,7 +372,7 b' CodeMirror.defineMode("clike", function('
311 }
372 }
312
373
313 function cppLooksLikeConstructor(word) {
374 function cppLooksLikeConstructor(word) {
314 var lastTwo = /(\w+)::(\w+)$/.exec(word);
375 var lastTwo = /(\w+)::~?(\w+)$/.exec(word);
315 return lastTwo && lastTwo[1] == lastTwo[2];
376 return lastTwo && lastTwo[1] == lastTwo[2];
316 }
377 }
317
378
@@ -363,29 +424,30 b' CodeMirror.defineMode("clike", function('
363 def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
424 def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
364 name: "clike",
425 name: "clike",
365 keywords: words(cKeywords),
426 keywords: words(cKeywords),
366 types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " +
427 types: cTypes,
367 "int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " +
428 blockKeywords: words(cBlockKeywords),
368 "uint32_t uint64_t"),
429 defKeywords: words(cDefKeywords),
369 blockKeywords: words("case do else for if switch while struct"),
370 defKeywords: words("struct"),
371 typeFirstDefinitions: true,
430 typeFirstDefinitions: true,
372 atoms: words("null true false"),
431 atoms: words("NULL true false"),
373 hooks: {"#": cppHook, "*": pointerHook},
432 isReservedIdentifier: cIsReservedIdentifier,
433 hooks: {
434 "#": cppHook,
435 "*": pointerHook,
436 },
374 modeProps: {fold: ["brace", "include"]}
437 modeProps: {fold: ["brace", "include"]}
375 });
438 });
376
439
377 def(["text/x-c++src", "text/x-c++hdr"], {
440 def(["text/x-c++src", "text/x-c++hdr"], {
378 name: "clike",
441 name: "clike",
379 keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " +
442 keywords: words(cKeywords + " " + cppKeywords),
380 "static_cast typeid catch operator template typename class friend private " +
443 types: cTypes,
381 "this using const_cast inline public throw virtual delete mutable protected " +
444 blockKeywords: words(cBlockKeywords + " class try catch"),
382 "alignas alignof constexpr decltype nullptr noexcept thread_local final " +
445 defKeywords: words(cDefKeywords + " class namespace"),
383 "static_assert override"),
384 types: words(cTypes + " bool wchar_t"),
385 blockKeywords: words("catch class do else finally for if struct switch try while"),
386 defKeywords: words("class namespace struct enum union"),
387 typeFirstDefinitions: true,
446 typeFirstDefinitions: true,
388 atoms: words("true false null"),
447 atoms: words("true false NULL nullptr"),
448 dontIndentStatements: /^template$/,
449 isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
450 isReservedIdentifier: cIsReservedIdentifier,
389 hooks: {
451 hooks: {
390 "#": cppHook,
452 "#": cppHook,
391 "*": pointerHook,
453 "*": pointerHook,
@@ -418,19 +480,22 b' CodeMirror.defineMode("clike", function('
418 def("text/x-java", {
480 def("text/x-java", {
419 name: "clike",
481 name: "clike",
420 keywords: words("abstract assert break case catch class const continue default " +
482 keywords: words("abstract assert break case catch class const continue default " +
421 "do else enum extends final finally float for goto if implements import " +
483 "do else enum extends final finally for goto if implements import " +
422 "instanceof interface native new package private protected public " +
484 "instanceof interface native new package private protected public " +
423 "return static strictfp super switch synchronized this throw throws transient " +
485 "return static strictfp super switch synchronized this throw throws transient " +
424 "try volatile while"),
486 "try volatile while @interface"),
425 types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " +
487 types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " +
426 "Integer Long Number Object Short String StringBuffer StringBuilder Void"),
488 "Integer Long Number Object Short String StringBuffer StringBuilder Void"),
427 blockKeywords: words("catch class do else finally for if switch try while"),
489 blockKeywords: words("catch class do else finally for if switch try while"),
428 defKeywords: words("class interface package enum"),
490 defKeywords: words("class interface enum @interface"),
429 typeFirstDefinitions: true,
491 typeFirstDefinitions: true,
430 atoms: words("true false null"),
492 atoms: words("true false null"),
431 endStatement: /^[;:]$/,
493 number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
432 hooks: {
494 hooks: {
433 "@": function(stream) {
495 "@": function(stream) {
496 // Don't match the @interface keyword.
497 if (stream.match('interface', false)) return false;
498
434 stream.eatWhile(/[\w\$_]/);
499 stream.eatWhile(/[\w\$_]/);
435 return "meta";
500 return "meta";
436 }
501 }
@@ -479,25 +544,42 b' CodeMirror.defineMode("clike", function('
479 return "string";
544 return "string";
480 }
545 }
481
546
547 function tokenNestedComment(depth) {
548 return function (stream, state) {
549 var ch
550 while (ch = stream.next()) {
551 if (ch == "*" && stream.eat("/")) {
552 if (depth == 1) {
553 state.tokenize = null
554 break
555 } else {
556 state.tokenize = tokenNestedComment(depth - 1)
557 return state.tokenize(stream, state)
558 }
559 } else if (ch == "/" && stream.eat("*")) {
560 state.tokenize = tokenNestedComment(depth + 1)
561 return state.tokenize(stream, state)
562 }
563 }
564 return "comment"
565 }
566 }
567
482 def("text/x-scala", {
568 def("text/x-scala", {
483 name: "clike",
569 name: "clike",
484 keywords: words(
570 keywords: words(
485
486 /* scala */
571 /* scala */
487 "abstract case catch class def do else extends final finally for forSome if " +
572 "abstract case catch class def do else extends final finally for forSome if " +
488 "implicit import lazy match new null object override package private protected return " +
573 "implicit import lazy match new null object override package private protected return " +
489 "sealed super this throw trait try type val var while with yield _ : = => <- <: " +
574 "sealed super this throw trait try type val var while with yield _ " +
490 "<% >: # @ " +
491
575
492 /* package scala */
576 /* package scala */
493 "assert assume require print println printf readLine readBoolean readByte readShort " +
577 "assert assume require print println printf readLine readBoolean readByte readShort " +
494 "readChar readInt readLong readFloat readDouble " +
578 "readChar readInt readLong readFloat readDouble"
495
496 ":: #:: "
497 ),
579 ),
498 types: words(
580 types: words(
499 "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
581 "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
500 "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
582 "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " +
501 "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
583 "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
502 "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
584 "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
503 "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " +
585 "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " +
@@ -509,11 +591,12 b' CodeMirror.defineMode("clike", function('
509 "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
591 "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
510 ),
592 ),
511 multiLineStrings: true,
593 multiLineStrings: true,
512 blockKeywords: words("catch class do else finally for forSome if match switch try while"),
594 blockKeywords: words("catch class enum do else finally for forSome if match switch try while"),
513 defKeywords: words("class def object package trait type val var"),
595 defKeywords: words("class enum def object package trait type val var"),
514 atoms: words("true false null"),
596 atoms: words("true false null"),
515 indentStatements: false,
597 indentStatements: false,
516 indentSwitch: false,
598 indentSwitch: false,
599 isOperatorChar: /[+\-*&%=<>!?|\/#:@]/,
517 hooks: {
600 hooks: {
518 "@": function(stream) {
601 "@": function(stream) {
519 stream.eatWhile(/[\w\$_]/);
602 stream.eatWhile(/[\w\$_]/);
@@ -527,9 +610,24 b' CodeMirror.defineMode("clike", function('
527 "'": function(stream) {
610 "'": function(stream) {
528 stream.eatWhile(/[\w\$_\xa1-\uffff]/);
611 stream.eatWhile(/[\w\$_\xa1-\uffff]/);
529 return "atom";
612 return "atom";
613 },
614 "=": function(stream, state) {
615 var cx = state.context
616 if (cx.type == "}" && cx.align && stream.eat(">")) {
617 state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev)
618 return "operator"
619 } else {
620 return false
530 }
621 }
531 },
622 },
532 modeProps: {closeBrackets: {triples: '"'}}
623
624 "/": function(stream, state) {
625 if (!stream.eat("*")) return false
626 state.tokenize = tokenNestedComment(1)
627 return state.tokenize(stream, state)
628 }
629 },
630 modeProps: {closeBrackets: {pairs: '()[]{}""', triples: '"'}}
533 });
631 });
534
632
535 function tokenKotlinString(tripleString){
633 function tokenKotlinString(tripleString){
@@ -553,33 +651,59 b' CodeMirror.defineMode("clike", function('
553 name: "clike",
651 name: "clike",
554 keywords: words(
652 keywords: words(
555 /*keywords*/
653 /*keywords*/
556 "package as typealias class interface this super val " +
654 "package as typealias class interface this super val operator " +
557 "var fun for is in This throw return " +
655 "var fun for is in This throw return annotation " +
558 "break continue object if else while do try when !in !is as? " +
656 "break continue object if else while do try when !in !is as? " +
559
657
560 /*soft keywords*/
658 /*soft keywords*/
561 "file import where by get set abstract enum open inner override private public internal " +
659 "file import where by get set abstract enum open inner override private public internal " +
562 "protected catch finally out final vararg reified dynamic companion constructor init " +
660 "protected catch finally out final vararg reified dynamic companion constructor init " +
563 "sealed field property receiver param sparam lateinit data inline noinline tailrec " +
661 "sealed field property receiver param sparam lateinit data inline noinline tailrec " +
564 "external annotation crossinline const operator infix"
662 "external annotation crossinline const operator infix suspend actual expect setparam"
565 ),
663 ),
566 types: words(
664 types: words(
567 /* package java.lang */
665 /* package java.lang */
568 "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
666 "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
569 "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
667 "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
570 "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
668 "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
571 "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
669 "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " +
670 "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " +
671 "LazyThreadSafetyMode LongArray Nothing ShortArray Unit"
572 ),
672 ),
573 intendSwitch: false,
673 intendSwitch: false,
574 indentStatements: false,
674 indentStatements: false,
575 multiLineStrings: true,
675 multiLineStrings: true,
676 number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
576 blockKeywords: words("catch class do else finally for if where try while enum"),
677 blockKeywords: words("catch class do else finally for if where try while enum"),
577 defKeywords: words("class val var object package interface fun"),
678 defKeywords: words("class val var object interface fun"),
578 atoms: words("true false null this"),
679 atoms: words("true false null this"),
579 hooks: {
680 hooks: {
681 "@": function(stream) {
682 stream.eatWhile(/[\w\$_]/);
683 return "meta";
684 },
685 '*': function(_stream, state) {
686 return state.prevToken == '.' ? 'variable' : 'operator';
687 },
580 '"': function(stream, state) {
688 '"': function(stream, state) {
581 state.tokenize = tokenKotlinString(stream.match('""'));
689 state.tokenize = tokenKotlinString(stream.match('""'));
582 return state.tokenize(stream, state);
690 return state.tokenize(stream, state);
691 },
692 "/": function(stream, state) {
693 if (!stream.eat("*")) return false;
694 state.tokenize = tokenNestedComment(1);
695 return state.tokenize(stream, state)
696 },
697 indent: function(state, ctx, textAfter, indentUnit) {
698 var firstChar = textAfter && textAfter.charAt(0);
699 if ((state.prevToken == "}" || state.prevToken == ")") && textAfter == "")
700 return state.indented;
701 if ((state.prevToken == "operator" && textAfter != "}" && state.context.type != "}") ||
702 state.prevToken == "variable" && firstChar == "." ||
703 (state.prevToken == "}" || state.prevToken == ")") && firstChar == ".")
704 return indentUnit * 2 + ctx.indented;
705 if (ctx.align && ctx.type == "}")
706 return ctx.indented + (state.context.type == (textAfter || "").charAt(0) ? 0 : indentUnit);
583 }
707 }
584 },
708 },
585 modeProps: {closeBrackets: {triples: '"'}}
709 modeProps: {closeBrackets: {triples: '"'}}
@@ -649,8 +773,8 b' CodeMirror.defineMode("clike", function('
649 keywords: words(cKeywords + "as atomic async call command component components configuration event generic " +
773 keywords: words(cKeywords + " as atomic async call command component components configuration event generic " +
650 "implementation includes interface module new norace nx_struct nx_union post provides " +
774 "implementation includes interface module new norace nx_struct nx_union post provides " +
651 "signal task uses abstract extends"),
775 "signal task uses abstract extends"),
652 types: words(cTypes),
776 types: cTypes,
653 blockKeywords: words("case do else for if switch while struct"),
777 blockKeywords: words(cBlockKeywords),
654 atoms: words("null true false"),
778 atoms: words("null true false"),
655 hooks: {"#": cppHook},
779 hooks: {"#": cppHook},
656 modeProps: {fold: ["brace", "include"]}
780 modeProps: {fold: ["brace", "include"]}
@@ -658,28 +782,67 b' CodeMirror.defineMode("clike", function('
658
782
659 def("text/x-objectivec", {
783 def("text/x-objectivec", {
660 name: "clike",
784 name: "clike",
661 keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginery BOOL Class bycopy byref id IMP in " +
785 keywords: words(cKeywords + " " + objCKeywords),
662 "inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),
786 types: objCTypes,
663 types: words(cTypes),
787 builtin: words(objCBuiltins),
664 atoms: words("YES NO NULL NILL ON OFF true false"),
788 blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized"),
789 defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class"),
790 dontIndentStatements: /^@.*$/,
791 typeFirstDefinitions: true,
792 atoms: words("YES NO NULL Nil nil true false nullptr"),
793 isReservedIdentifier: cIsReservedIdentifier,
665 hooks: {
794 hooks: {
666 "@": function(stream) {
795 "#": cppHook,
667 stream.eatWhile(/[\w\$]/);
796 "*": pointerHook,
668 return "keyword";
669 },
797 },
798 modeProps: {fold: ["brace", "include"]}
799 });
800
801 def("text/x-objectivec++", {
802 name: "clike",
803 keywords: words(cKeywords + " " + objCKeywords + " " + cppKeywords),
804 types: objCTypes,
805 builtin: words(objCBuiltins),
806 blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized class try catch"),
807 defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class class namespace"),
808 dontIndentStatements: /^@.*$|^template$/,
809 typeFirstDefinitions: true,
810 atoms: words("YES NO NULL Nil nil true false nullptr"),
811 isReservedIdentifier: cIsReservedIdentifier,
812 hooks: {
670 "#": cppHook,
813 "#": cppHook,
671 indent: function(_state, ctx, textAfter) {
814 "*": pointerHook,
672 if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented
815 "u": cpp11StringHook,
816 "U": cpp11StringHook,
817 "L": cpp11StringHook,
818 "R": cpp11StringHook,
819 "0": cpp14Literal,
820 "1": cpp14Literal,
821 "2": cpp14Literal,
822 "3": cpp14Literal,
823 "4": cpp14Literal,
824 "5": cpp14Literal,
825 "6": cpp14Literal,
826 "7": cpp14Literal,
827 "8": cpp14Literal,
828 "9": cpp14Literal,
829 token: function(stream, state, style) {
830 if (style == "variable" && stream.peek() == "(" &&
831 (state.prevToken == ";" || state.prevToken == null ||
832 state.prevToken == "}") &&
833 cppLooksLikeConstructor(stream.current()))
834 return "def";
673 }
835 }
674 },
836 },
675 modeProps: {fold: "brace"}
837 namespaceSeparator: "::",
838 modeProps: {fold: ["brace", "include"]}
676 });
839 });
677
840
678 def("text/x-squirrel", {
841 def("text/x-squirrel", {
679 name: "clike",
842 name: "clike",
680 keywords: words("base break clone continue const default delete enum extends function in class" +
843 keywords: words("base break clone continue const default delete enum extends function in class" +
681 " foreach local resume return this throw typeof yield constructor instanceof static"),
844 " foreach local resume return this throw typeof yield constructor instanceof static"),
682 types: words(cTypes),
845 types: cTypes,
683 blockKeywords: words("case catch class else for foreach if switch try while"),
846 blockKeywords: words("case catch class else for foreach if switch try while"),
684 defKeywords: words("function local class"),
847 defKeywords: words("function local class"),
685 typeFirstDefinitions: true,
848 typeFirstDefinitions: true,
@@ -757,7 +920,7 b' CodeMirror.defineMode("clike", function('
757 return "atom";
920 return "atom";
758 },
921 },
759 token: function(_stream, state, style) {
922 token: function(_stream, state, style) {
760 if ((style == "variable" || style == "variable-3") &&
923 if ((style == "variable" || style == "type") &&
761 state.prevToken == ".") {
924 state.prevToken == ".") {
762 return "variable-2";
925 return "variable-2";
763 }
926 }
@@ -1,15 +1,10 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 /**
5 * Author: Hans Engel
6 * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun)
7 */
8
3
9 (function(mod) {
4 (function(mod) {
10 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports === "object" && typeof module === "object") // CommonJS
11 mod(require("../../lib/codemirror"));
6 mod(require("../../lib/codemirror"));
12 else if (typeof define == "function" && define.amd) // AMD
7 else if (typeof define === "function" && define.amd) // AMD
13 define(["../../lib/codemirror"], mod);
8 define(["../../lib/codemirror"], mod);
14 else // Plain browser env
9 else // Plain browser env
15 mod(CodeMirror);
10 mod(CodeMirror);
@@ -17,225 +12,272 b''
17 "use strict";
12 "use strict";
18
13
19 CodeMirror.defineMode("clojure", function (options) {
14 CodeMirror.defineMode("clojure", function (options) {
20 var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", CHARACTER = "string-2",
15 var atoms = ["false", "nil", "true"];
21 ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword", VAR = "variable";
16 var specialForms = [".", "catch", "def", "do", "if", "monitor-enter",
22 var INDENT_WORD_SKIP = options.indentUnit || 2;
17 "monitor-exit", "new", "quote", "recur", "set!", "throw", "try", "var"];
23 var NORMAL_INDENT_UNIT = options.indentUnit || 2;
18 var coreSymbols = ["*", "*'", "*1", "*2", "*3", "*agent*",
19 "*allow-unresolved-vars*", "*assert*", "*clojure-version*",
20 "*command-line-args*", "*compile-files*", "*compile-path*",
21 "*compiler-options*", "*data-readers*", "*default-data-reader-fn*", "*e",
22 "*err*", "*file*", "*flush-on-newline*", "*fn-loader*", "*in*",
23 "*math-context*", "*ns*", "*out*", "*print-dup*", "*print-length*",
24 "*print-level*", "*print-meta*", "*print-namespace-maps*",
25 "*print-readably*", "*read-eval*", "*reader-resolver*", "*source-path*",
26 "*suppress-read*", "*unchecked-math*", "*use-context-classloader*",
27 "*verbose-defrecords*", "*warn-on-reflection*", "+", "+'", "-", "-'",
28 "->", "->>", "->ArrayChunk", "->Eduction", "->Vec", "->VecNode",
29 "->VecSeq", "-cache-protocol-fn", "-reset-methods", "..", "/", "<", "<=",
30 "=", "==", ">", ">=", "EMPTY-NODE", "Inst", "StackTraceElement->vec",
31 "Throwable->map", "accessor", "aclone", "add-classpath", "add-watch",
32 "agent", "agent-error", "agent-errors", "aget", "alength", "alias",
33 "all-ns", "alter", "alter-meta!", "alter-var-root", "amap", "ancestors",
34 "and", "any?", "apply", "areduce", "array-map", "as->", "aset",
35 "aset-boolean", "aset-byte", "aset-char", "aset-double", "aset-float",
36 "aset-int", "aset-long", "aset-short", "assert", "assoc", "assoc!",
37 "assoc-in", "associative?", "atom", "await", "await-for", "await1",
38 "bases", "bean", "bigdec", "bigint", "biginteger", "binding", "bit-and",
39 "bit-and-not", "bit-clear", "bit-flip", "bit-not", "bit-or", "bit-set",
40 "bit-shift-left", "bit-shift-right", "bit-test", "bit-xor", "boolean",
41 "boolean-array", "boolean?", "booleans", "bound-fn", "bound-fn*",
42 "bound?", "bounded-count", "butlast", "byte", "byte-array", "bytes",
43 "bytes?", "case", "cast", "cat", "char", "char-array",
44 "char-escape-string", "char-name-string", "char?", "chars", "chunk",
45 "chunk-append", "chunk-buffer", "chunk-cons", "chunk-first", "chunk-next",
46 "chunk-rest", "chunked-seq?", "class", "class?", "clear-agent-errors",
47 "clojure-version", "coll?", "comment", "commute", "comp", "comparator",
48 "compare", "compare-and-set!", "compile", "complement", "completing",
49 "concat", "cond", "cond->", "cond->>", "condp", "conj", "conj!", "cons",
50 "constantly", "construct-proxy", "contains?", "count", "counted?",
51 "create-ns", "create-struct", "cycle", "dec", "dec'", "decimal?",
52 "declare", "dedupe", "default-data-readers", "definline", "definterface",
53 "defmacro", "defmethod", "defmulti", "defn", "defn-", "defonce",
54 "defprotocol", "defrecord", "defstruct", "deftype", "delay", "delay?",
55 "deliver", "denominator", "deref", "derive", "descendants", "destructure",
56 "disj", "disj!", "dissoc", "dissoc!", "distinct", "distinct?", "doall",
57 "dorun", "doseq", "dosync", "dotimes", "doto", "double", "double-array",
58 "double?", "doubles", "drop", "drop-last", "drop-while", "eduction",
59 "empty", "empty?", "ensure", "ensure-reduced", "enumeration-seq",
60 "error-handler", "error-mode", "eval", "even?", "every-pred", "every?",
61 "ex-data", "ex-info", "extend", "extend-protocol", "extend-type",
62 "extenders", "extends?", "false?", "ffirst", "file-seq", "filter",
63 "filterv", "find", "find-keyword", "find-ns", "find-protocol-impl",
64 "find-protocol-method", "find-var", "first", "flatten", "float",
65 "float-array", "float?", "floats", "flush", "fn", "fn?", "fnext", "fnil",
66 "for", "force", "format", "frequencies", "future", "future-call",
67 "future-cancel", "future-cancelled?", "future-done?", "future?",
68 "gen-class", "gen-interface", "gensym", "get", "get-in", "get-method",
69 "get-proxy-class", "get-thread-bindings", "get-validator", "group-by",
70 "halt-when", "hash", "hash-combine", "hash-map", "hash-ordered-coll",
71 "hash-set", "hash-unordered-coll", "ident?", "identical?", "identity",
72 "if-let", "if-not", "if-some", "ifn?", "import", "in-ns", "inc", "inc'",
73 "indexed?", "init-proxy", "inst-ms", "inst-ms*", "inst?", "instance?",
74 "int", "int-array", "int?", "integer?", "interleave", "intern",
75 "interpose", "into", "into-array", "ints", "io!", "isa?", "iterate",
76 "iterator-seq", "juxt", "keep", "keep-indexed", "key", "keys", "keyword",
77 "keyword?", "last", "lazy-cat", "lazy-seq", "let", "letfn", "line-seq",
78 "list", "list*", "list?", "load", "load-file", "load-reader",
79 "load-string", "loaded-libs", "locking", "long", "long-array", "longs",
80 "loop", "macroexpand", "macroexpand-1", "make-array", "make-hierarchy",
81 "map", "map-entry?", "map-indexed", "map?", "mapcat", "mapv", "max",
82 "max-key", "memfn", "memoize", "merge", "merge-with", "meta",
83 "method-sig", "methods", "min", "min-key", "mix-collection-hash", "mod",
84 "munge", "name", "namespace", "namespace-munge", "nat-int?", "neg-int?",
85 "neg?", "newline", "next", "nfirst", "nil?", "nnext", "not", "not-any?",
86 "not-empty", "not-every?", "not=", "ns", "ns-aliases", "ns-imports",
87 "ns-interns", "ns-map", "ns-name", "ns-publics", "ns-refers",
88 "ns-resolve", "ns-unalias", "ns-unmap", "nth", "nthnext", "nthrest",
89 "num", "number?", "numerator", "object-array", "odd?", "or", "parents",
90 "partial", "partition", "partition-all", "partition-by", "pcalls", "peek",
91 "persistent!", "pmap", "pop", "pop!", "pop-thread-bindings", "pos-int?",
92 "pos?", "pr", "pr-str", "prefer-method", "prefers",
93 "primitives-classnames", "print", "print-ctor", "print-dup",
94 "print-method", "print-simple", "print-str", "printf", "println",
95 "println-str", "prn", "prn-str", "promise", "proxy",
96 "proxy-call-with-super", "proxy-mappings", "proxy-name", "proxy-super",
97 "push-thread-bindings", "pvalues", "qualified-ident?",
98 "qualified-keyword?", "qualified-symbol?", "quot", "rand", "rand-int",
99 "rand-nth", "random-sample", "range", "ratio?", "rational?",
100 "rationalize", "re-find", "re-groups", "re-matcher", "re-matches",
101 "re-pattern", "re-seq", "read", "read-line", "read-string",
102 "reader-conditional", "reader-conditional?", "realized?", "record?",
103 "reduce", "reduce-kv", "reduced", "reduced?", "reductions", "ref",
104 "ref-history-count", "ref-max-history", "ref-min-history", "ref-set",
105 "refer", "refer-clojure", "reify", "release-pending-sends", "rem",
106 "remove", "remove-all-methods", "remove-method", "remove-ns",
107 "remove-watch", "repeat", "repeatedly", "replace", "replicate", "require",
108 "reset!", "reset-meta!", "reset-vals!", "resolve", "rest",
109 "restart-agent", "resultset-seq", "reverse", "reversible?", "rseq",
110 "rsubseq", "run!", "satisfies?", "second", "select-keys", "send",
111 "send-off", "send-via", "seq", "seq?", "seqable?", "seque", "sequence",
112 "sequential?", "set", "set-agent-send-executor!",
113 "set-agent-send-off-executor!", "set-error-handler!", "set-error-mode!",
114 "set-validator!", "set?", "short", "short-array", "shorts", "shuffle",
115 "shutdown-agents", "simple-ident?", "simple-keyword?", "simple-symbol?",
116 "slurp", "some", "some->", "some->>", "some-fn", "some?", "sort",
117 "sort-by", "sorted-map", "sorted-map-by", "sorted-set", "sorted-set-by",
118 "sorted?", "special-symbol?", "spit", "split-at", "split-with", "str",
119 "string?", "struct", "struct-map", "subs", "subseq", "subvec", "supers",
120 "swap!", "swap-vals!", "symbol", "symbol?", "sync", "tagged-literal",
121 "tagged-literal?", "take", "take-last", "take-nth", "take-while", "test",
122 "the-ns", "thread-bound?", "time", "to-array", "to-array-2d",
123 "trampoline", "transduce", "transient", "tree-seq", "true?", "type",
124 "unchecked-add", "unchecked-add-int", "unchecked-byte", "unchecked-char",
125 "unchecked-dec", "unchecked-dec-int", "unchecked-divide-int",
126 "unchecked-double", "unchecked-float", "unchecked-inc",
127 "unchecked-inc-int", "unchecked-int", "unchecked-long",
128 "unchecked-multiply", "unchecked-multiply-int", "unchecked-negate",
129 "unchecked-negate-int", "unchecked-remainder-int", "unchecked-short",
130 "unchecked-subtract", "unchecked-subtract-int", "underive", "unquote",
131 "unquote-splicing", "unreduced", "unsigned-bit-shift-right", "update",
132 "update-in", "update-proxy", "uri?", "use", "uuid?", "val", "vals",
133 "var-get", "var-set", "var?", "vary-meta", "vec", "vector", "vector-of",
134 "vector?", "volatile!", "volatile?", "vreset!", "vswap!", "when",
135 "when-first", "when-let", "when-not", "when-some", "while",
136 "with-bindings", "with-bindings*", "with-in-str", "with-loading-context",
137 "with-local-vars", "with-meta", "with-open", "with-out-str",
138 "with-precision", "with-redefs", "with-redefs-fn", "xml-seq", "zero?",
139 "zipmap"];
140 var haveBodyParameter = [
141 "->", "->>", "as->", "binding", "bound-fn", "case", "catch", "comment",
142 "cond", "cond->", "cond->>", "condp", "def", "definterface", "defmethod",
143 "defn", "defmacro", "defprotocol", "defrecord", "defstruct", "deftype",
144 "do", "doseq", "dotimes", "doto", "extend", "extend-protocol",
145 "extend-type", "fn", "for", "future", "if", "if-let", "if-not", "if-some",
146 "let", "letfn", "locking", "loop", "ns", "proxy", "reify", "struct-map",
147 "some->", "some->>", "try", "when", "when-first", "when-let", "when-not",
148 "when-some", "while", "with-bindings", "with-bindings*", "with-in-str",
149 "with-loading-context", "with-local-vars", "with-meta", "with-open",
150 "with-out-str", "with-precision", "with-redefs", "with-redefs-fn"];
24
151
25 function makeKeywords(str) {
152 CodeMirror.registerHelper("hintWords", "clojure",
26 var obj = {}, words = str.split(" ");
153 [].concat(atoms, specialForms, coreSymbols));
154
155 var atom = createLookupMap(atoms);
156 var specialForm = createLookupMap(specialForms);
157 var coreSymbol = createLookupMap(coreSymbols);
158 var hasBodyParameter = createLookupMap(haveBodyParameter);
159 var delimiter = /^(?:[\\\[\]\s"(),;@^`{}~]|$)/;
160 var numberLiteral = /^(?:[+\-]?\d+(?:(?:N|(?:[eE][+\-]?\d+))|(?:\.?\d*(?:M|(?:[eE][+\-]?\d+))?)|\/\d+|[xX][0-9a-fA-F]+|r[0-9a-zA-Z]+)?(?=[\\\[\]\s"#'(),;@^`{}~]|$))/;
161 var characterLiteral = /^(?:\\(?:backspace|formfeed|newline|return|space|tab|o[0-7]{3}|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{4}|.)?(?=[\\\[\]\s"(),;@^`{}~]|$))/;
162
163 // simple-namespace := /^[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*/
164 // simple-symbol := /^(?:\/|[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)/
165 // qualified-symbol := (<simple-namespace>(<.><simple-namespace>)*</>)?<simple-symbol>
166 var qualifiedSymbol = /^(?:(?:[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*(?:\.[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)*\/)?(?:\/|[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)*(?=[\\\[\]\s"(),;@^`{}~]|$))/;
167
168 function base(stream, state) {
169 if (stream.eatSpace() || stream.eat(",")) return ["space", null];
170 if (stream.match(numberLiteral)) return [null, "number"];
171 if (stream.match(characterLiteral)) return [null, "string-2"];
172 if (stream.eat(/^"/)) return (state.tokenize = inString)(stream, state);
173 if (stream.eat(/^[(\[{]/)) return ["open", "bracket"];
174 if (stream.eat(/^[)\]}]/)) return ["close", "bracket"];
175 if (stream.eat(/^;/)) {stream.skipToEnd(); return ["space", "comment"];}
176 if (stream.eat(/^[#'@^`~]/)) return [null, "meta"];
177
178 var matches = stream.match(qualifiedSymbol);
179 var symbol = matches && matches[0];
180
181 if (!symbol) {
182 // advance stream by at least one character so we don't get stuck.
183 stream.next();
184 stream.eatWhile(function (c) {return !is(c, delimiter);});
185 return [null, "error"];
186 }
187
188 if (symbol === "comment" && state.lastToken === "(")
189 return (state.tokenize = inComment)(stream, state);
190 if (is(symbol, atom) || symbol.charAt(0) === ":") return ["symbol", "atom"];
191 if (is(symbol, specialForm) || is(symbol, coreSymbol)) return ["symbol", "keyword"];
192 if (state.lastToken === "(") return ["symbol", "builtin"]; // other operator
193
194 return ["symbol", "variable"];
195 }
196
197 function inString(stream, state) {
198 var escaped = false, next;
199
200 while (next = stream.next()) {
201 if (next === "\"" && !escaped) {state.tokenize = base; break;}
202 escaped = !escaped && next === "\\";
203 }
204
205 return [null, "string"];
206 }
207
208 function inComment(stream, state) {
209 var parenthesisCount = 1;
210 var next;
211
212 while (next = stream.next()) {
213 if (next === ")") parenthesisCount--;
214 if (next === "(") parenthesisCount++;
215 if (parenthesisCount === 0) {
216 stream.backUp(1);
217 state.tokenize = base;
218 break;
219 }
220 }
221
222 return ["space", "comment"];
223 }
224
225 function createLookupMap(words) {
226 var obj = {};
227
27 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
228 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
229
28 return obj;
230 return obj;
29 }
231 }
30
232
31 var atoms = makeKeywords("true false nil");
233 function is(value, test) {
32
234 if (test instanceof RegExp) return test.test(value);
33 var keywords = makeKeywords(
235 if (test instanceof Object) return test.propertyIsEnumerable(value);
34 "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle");
35
36 var builtins = makeKeywords(
37 "* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> ->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? declare default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int rand-nth range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap *default-data-reader-fn* as-> cond-> cond->> reduced reduced? send-via set-agent-send-executor! set-agent-send-off-executor! some-> some->>");
38
39 var indentKeys = makeKeywords(
40 // Built-ins
41 "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch " +
42
43 // Binding forms
44 "let letfn binding loop for doseq dotimes when-let if-let " +
45
46 // Data structures
47 "defstruct struct-map assoc " +
48
49 // clojure.test
50 "testing deftest " +
51
52 // contrib
53 "handler-case handle dotrace deftrace");
54
55 var tests = {
56 digit: /\d/,
57 digit_or_colon: /[\d:]/,
58 hex: /[0-9a-f]/i,
59 sign: /[+-]/,
60 exponent: /e/i,
61 keyword_char: /[^\s\(\[\;\)\]]/,
62 symbol: /[\w*+!\-\._?:<>\/\xa1-\uffff]/,
63 block_indent: /^(?:def|with)[^\/]+$|\/(?:def|with)/
64 };
65
66 function stateStack(indent, type, prev) { // represents a state stack object
67 this.indent = indent;
68 this.type = type;
69 this.prev = prev;
70 }
71
72 function pushStack(state, indent, type) {
73 state.indentStack = new stateStack(indent, type, state.indentStack);
74 }
75
76 function popStack(state) {
77 state.indentStack = state.indentStack.prev;
78 }
79
80 function isNumber(ch, stream){
81 // hex
82 if ( ch === '0' && stream.eat(/x/i) ) {
83 stream.eatWhile(tests.hex);
84 return true;
85 }
86
87 // leading sign
88 if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) {
89 stream.eat(tests.sign);
90 ch = stream.next();
91 }
92
93 if ( tests.digit.test(ch) ) {
94 stream.eat(ch);
95 stream.eatWhile(tests.digit);
96
97 if ( '.' == stream.peek() ) {
98 stream.eat('.');
99 stream.eatWhile(tests.digit);
100 } else if ('/' == stream.peek() ) {
101 stream.eat('/');
102 stream.eatWhile(tests.digit);
103 }
104
105 if ( stream.eat(tests.exponent) ) {
106 stream.eat(tests.sign);
107 stream.eatWhile(tests.digit);
108 }
109
110 return true;
111 }
112
113 return false;
114 }
115
116 // Eat character that starts after backslash \
117 function eatCharacter(stream) {
118 var first = stream.next();
119 // Read special literals: backspace, newline, space, return.
120 // Just read all lowercase letters.
121 if (first && first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) {
122 return;
123 }
124 // Read unicode character: \u1000 \uA0a1
125 if (first === "u") {
126 stream.match(/[0-9a-z]{4}/i, true);
127 }
128 }
236 }
129
237
130 return {
238 return {
131 startState: function () {
239 startState: function () {
132 return {
240 return {
133 indentStack: null,
241 ctx: {prev: null, start: 0, indentTo: 0},
134 indentation: 0,
242 lastToken: null,
135 mode: false
243 tokenize: base
136 };
244 };
137 },
245 },
138
246
139 token: function (stream, state) {
247 token: function (stream, state) {
140 if (state.indentStack == null && stream.sol()) {
248 if (stream.sol() && (typeof state.ctx.indentTo !== "number"))
141 // update indentation, but only if indentStack is empty
249 state.ctx.indentTo = state.ctx.start + 1;
142 state.indentation = stream.indentation();
250
251 var typeStylePair = state.tokenize(stream, state);
252 var type = typeStylePair[0];
253 var style = typeStylePair[1];
254 var current = stream.current();
255
256 if (type !== "space") {
257 if (state.lastToken === "(" && state.ctx.indentTo === null) {
258 if (type === "symbol" && is(current, hasBodyParameter))
259 state.ctx.indentTo = state.ctx.start + options.indentUnit;
260 else state.ctx.indentTo = "next";
261 } else if (state.ctx.indentTo === "next") {
262 state.ctx.indentTo = stream.column();
143 }
263 }
144
264
145 // skip spaces
265 state.lastToken = current;
146 if (state.mode != "string" && stream.eatSpace()) {
147 return null;
148 }
149 var returnType = null;
150
151 switch(state.mode){
152 case "string": // multi-line string parsing mode
153 var next, escaped = false;
154 while ((next = stream.next()) != null) {
155 if (next == "\"" && !escaped) {
156
157 state.mode = false;
158 break;
159 }
160 escaped = !escaped && next == "\\";
161 }
162 returnType = STRING; // continue on in string mode
163 break;
164 default: // default parsing mode
165 var ch = stream.next();
166
167 if (ch == "\"") {
168 state.mode = "string";
169 returnType = STRING;
170 } else if (ch == "\\") {
171 eatCharacter(stream);
172 returnType = CHARACTER;
173 } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) {
174 returnType = ATOM;
175 } else if (ch == ";") { // comment
176 stream.skipToEnd(); // rest of the line is a comment
177 returnType = COMMENT;
178 } else if (isNumber(ch,stream)){
179 returnType = NUMBER;
180 } else if (ch == "(" || ch == "[" || ch == "{" ) {
181 var keyWord = '', indentTemp = stream.column(), letter;
182 /**
183 Either
184 (indent-word ..
185 (non-indent-word ..
186 (;something else, bracket, etc.
187 */
188
189 if (ch == "(") while ((letter = stream.eat(tests.keyword_char)) != null) {
190 keyWord += letter;
191 }
266 }
192
267
193 if (keyWord.length > 0 && (indentKeys.propertyIsEnumerable(keyWord) ||
268 if (type === "open")
194 tests.block_indent.test(keyWord))) { // indent-word
269 state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
195 pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
270 else if (type === "close") state.ctx = state.ctx.prev || state.ctx;
196 } else { // non-indent word
197 // we continue eating the spaces
198 stream.eatSpace();
199 if (stream.eol() || stream.peek() == ";") {
200 // nothing significant after
201 // we restart indentation the user defined spaces after
202 pushStack(state, indentTemp + NORMAL_INDENT_UNIT, ch);
203 } else {
204 pushStack(state, indentTemp + stream.current().length, ch); // else we match
205 }
206 }
207 stream.backUp(stream.current().length - 1); // undo all the eating
208
271
209 returnType = BRACKET;
272 return style;
210 } else if (ch == ")" || ch == "]" || ch == "}") {
211 returnType = BRACKET;
212 if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : (ch == "]" ? "[" :"{"))) {
213 popStack(state);
214 }
215 } else if ( ch == ":" ) {
216 stream.eatWhile(tests.symbol);
217 return ATOM;
218 } else {
219 stream.eatWhile(tests.symbol);
220
221 if (keywords && keywords.propertyIsEnumerable(stream.current())) {
222 returnType = KEYWORD;
223 } else if (builtins && builtins.propertyIsEnumerable(stream.current())) {
224 returnType = BUILTIN;
225 } else if (atoms && atoms.propertyIsEnumerable(stream.current())) {
226 returnType = ATOM;
227 } else {
228 returnType = VAR;
229 }
230 }
231 }
232
233 return returnType;
234 },
273 },
235
274
236 indent: function (state) {
275 indent: function (state) {
237 if (state.indentStack == null) return state.indentation;
276 var i = state.ctx.indentTo;
238 return state.indentStack.indent;
277
278 return (typeof i === "number") ?
279 i :
280 state.ctx.start + 1;
239 },
281 },
240
282
241 closeBrackets: {pairs: "()[]{}\"\""},
283 closeBrackets: {pairs: "()[]{}\"\""},
@@ -245,5 +287,6 b' CodeMirror.defineMode("clojure", functio'
245
287
246 CodeMirror.defineMIME("text/x-clojure", "clojure");
288 CodeMirror.defineMIME("text/x-clojure", "clojure");
247 CodeMirror.defineMIME("text/x-clojurescript", "clojure");
289 CodeMirror.defineMIME("text/x-clojurescript", "clojure");
290 CodeMirror.defineMIME("application/edn", "clojure");
248
291
249 });
292 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object")
5 if (typeof exports == "object" && typeof module == "object")
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /**
4 /**
5 * Author: Gautam Mehta
5 * Author: Gautam Mehta
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /**
4 /**
5 * Link to the project's GitHub page:
5 * Link to the project's GitHub page:
@@ -349,6 +349,10 b' CodeMirror.defineMode("coffeescript", fu'
349 return external;
349 return external;
350 });
350 });
351
351
352 // IANA registered media type
353 // https://www.iana.org/assignments/media-types/
354 CodeMirror.defineMIME("application/vnd.coffeescript", "coffeescript");
355
352 CodeMirror.defineMIME("text/x-coffeescript", "coffeescript");
356 CodeMirror.defineMIME("text/x-coffeescript", "coffeescript");
353 CodeMirror.defineMIME("text/coffeescript", "coffeescript");
357 CodeMirror.defineMIME("text/coffeescript", "coffeescript");
354
358
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -43,11 +43,12 b' CodeMirror.defineMode("commonlisp", func'
43 else { stream.skipToEnd(); return "error"; }
43 else { stream.skipToEnd(); return "error"; }
44 } else if (ch == "#") {
44 } else if (ch == "#") {
45 var ch = stream.next();
45 var ch = stream.next();
46 if (ch == "[") { type = "open"; return "bracket"; }
46 if (ch == "(") { type = "open"; return "bracket"; }
47 else if (/[+\-=\.']/.test(ch)) return null;
47 else if (/[+\-=\.']/.test(ch)) return null;
48 else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null;
48 else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null;
49 else if (ch == "|") return (state.tokenize = inComment)(stream, state);
49 else if (ch == "|") return (state.tokenize = inComment)(stream, state);
50 else if (ch == ":") { readSym(stream); return "meta"; }
50 else if (ch == ":") { readSym(stream); return "meta"; }
51 else if (ch == "\\") { stream.next(); readSym(stream); return "string-2" }
51 else return "error";
52 else return "error";
52 } else {
53 } else {
53 var name = readSym(stream);
54 var name = readSym(stream);
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -29,26 +29,22 b''
29 var types = /^[A-Z_\u009F-\uFFFF][a-zA-Z0-9_\u009F-\uFFFF]*/;
29 var types = /^[A-Z_\u009F-\uFFFF][a-zA-Z0-9_\u009F-\uFFFF]*/;
30 var keywords = wordRegExp([
30 var keywords = wordRegExp([
31 "abstract", "alias", "as", "asm", "begin", "break", "case", "class", "def", "do",
31 "abstract", "alias", "as", "asm", "begin", "break", "case", "class", "def", "do",
32 "else", "elsif", "end", "ensure", "enum", "extend", "for", "fun", "if", "ifdef",
32 "else", "elsif", "end", "ensure", "enum", "extend", "for", "fun", "if",
33 "include", "instance_sizeof", "lib", "macro", "module", "next", "of", "out", "pointerof",
33 "include", "instance_sizeof", "lib", "macro", "module", "next", "of", "out", "pointerof",
34 "private", "protected", "rescue", "return", "require", "sizeof", "struct",
34 "private", "protected", "rescue", "return", "require", "select", "sizeof", "struct",
35 "super", "then", "type", "typeof", "union", "unless", "until", "when", "while", "with",
35 "super", "then", "type", "typeof", "uninitialized", "union", "unless", "until", "when", "while", "with",
36 "yield", "__DIR__", "__FILE__", "__LINE__"
36 "yield", "__DIR__", "__END_LINE__", "__FILE__", "__LINE__"
37 ]);
37 ]);
38 var atomWords = wordRegExp(["true", "false", "nil", "self"]);
38 var atomWords = wordRegExp(["true", "false", "nil", "self"]);
39 var indentKeywordsArray = [
39 var indentKeywordsArray = [
40 "def", "fun", "macro",
40 "def", "fun", "macro",
41 "class", "module", "struct", "lib", "enum", "union",
41 "class", "module", "struct", "lib", "enum", "union",
42 "if", "unless", "case", "while", "until", "begin", "then",
42 "do", "for"
43 "do",
44 "for", "ifdef"
45 ];
43 ];
46 var indentKeywords = wordRegExp(indentKeywordsArray);
44 var indentKeywords = wordRegExp(indentKeywordsArray);
47 var dedentKeywordsArray = [
45 var indentExpressionKeywordsArray = ["if", "unless", "case", "while", "until", "begin", "then"];
48 "end",
46 var indentExpressionKeywords = wordRegExp(indentExpressionKeywordsArray);
49 "else", "elsif",
47 var dedentKeywordsArray = ["end", "else", "elsif", "rescue", "ensure"];
50 "rescue", "ensure"
51 ];
52 var dedentKeywords = wordRegExp(dedentKeywordsArray);
48 var dedentKeywords = wordRegExp(dedentKeywordsArray);
53 var dedentPunctualsArray = ["\\)", "\\}", "\\]"];
49 var dedentPunctualsArray = ["\\)", "\\}", "\\]"];
54 var dedentPunctuals = new RegExp("^(?:" + dedentPunctualsArray.join("|") + ")$");
50 var dedentPunctuals = new RegExp("^(?:" + dedentPunctualsArray.join("|") + ")$");
@@ -90,12 +86,15 b''
90 } else if (state.lastToken == ".") {
86 } else if (state.lastToken == ".") {
91 return "property";
87 return "property";
92 } else if (keywords.test(matched)) {
88 } else if (keywords.test(matched)) {
93 if (state.lastToken != "abstract" && indentKeywords.test(matched)) {
89 if (indentKeywords.test(matched)) {
94 if (!(matched == "fun" && state.blocks.indexOf("lib") >= 0)) {
90 if (!(matched == "fun" && state.blocks.indexOf("lib") >= 0) && !(matched == "def" && state.lastToken == "abstract")) {
95 state.blocks.push(matched);
91 state.blocks.push(matched);
96 state.currentIndent += 1;
92 state.currentIndent += 1;
97 }
93 }
98 } else if (dedentKeywords.test(matched)) {
94 } else if ((state.lastStyle == "operator" || !state.lastStyle) && indentExpressionKeywords.test(matched)) {
95 state.blocks.push(matched);
96 state.currentIndent += 1;
97 } else if (matched == "end") {
99 state.blocks.pop();
98 state.blocks.pop();
100 state.currentIndent -= 1;
99 state.currentIndent -= 1;
101 }
100 }
@@ -124,12 +123,6 b''
124 return "variable-2";
123 return "variable-2";
125 }
124 }
126
125
127 // Global variables
128 if (stream.eat("$")) {
129 stream.eat(/[0-9]+|\?/) || stream.match(idents) || stream.match(types);
130 return "variable-3";
131 }
132
133 // Constants and types
126 // Constants and types
134 if (stream.match(types)) {
127 if (stream.match(types)) {
135 return "tag";
128 return "tag";
@@ -165,6 +158,9 b''
165 } else if (stream.match("%w")) {
158 } else if (stream.match("%w")) {
166 embed = false;
159 embed = false;
167 delim = stream.next();
160 delim = stream.next();
161 } else if (stream.match("%q")) {
162 embed = false;
163 delim = stream.next();
168 } else {
164 } else {
169 if(delim = stream.match(/^%([^\w\s=])/)) {
165 if(delim = stream.match(/^%([^\w\s=])/)) {
170 delim = delim[1];
166 delim = delim[1];
@@ -183,6 +179,11 b''
183 return chain(tokenQuote(delim, style, embed), stream, state);
179 return chain(tokenQuote(delim, style, embed), stream, state);
184 }
180 }
185
181
182 // Here Docs
183 if (matched = stream.match(/^<<-('?)([A-Z]\w*)\1/)) {
184 return chain(tokenHereDoc(matched[2], !matched[1]), stream, state)
185 }
186
186 // Characters
187 // Characters
187 if (stream.eat("'")) {
188 if (stream.eat("'")) {
188 stream.match(/^(?:[^']|\\(?:[befnrtv0'"]|[0-7]{3}|u(?:[0-9a-fA-F]{4}|\{[0-9a-fA-F]{1,6}\})))/);
189 stream.match(/^(?:[^']|\\(?:[befnrtv0'"]|[0-7]{3}|u(?:[0-9a-fA-F]{4}|\{[0-9a-fA-F]{1,6}\})))/);
@@ -202,14 +203,14 b''
202 return "number";
203 return "number";
203 }
204 }
204
205
205 if (stream.eat(/\d/)) {
206 if (stream.eat(/^\d/)) {
206 stream.match(/^\d*(?:\.\d+)?(?:[eE][+-]?\d+)?/);
207 stream.match(/^\d*(?:\.\d+)?(?:[eE][+-]?\d+)?/);
207 return "number";
208 return "number";
208 }
209 }
209
210
210 // Operators
211 // Operators
211 if (stream.match(operators)) {
212 if (stream.match(operators)) {
212 stream.eat("="); // Operators can follow assigin symbol.
213 stream.eat("="); // Operators can follow assign symbol.
213 return "operator";
214 return "operator";
214 }
215 }
215
216
@@ -339,7 +340,7 b''
339 return style;
340 return style;
340 }
341 }
341
342
342 escaped = ch == "\\";
343 escaped = embed && ch == "\\";
343 } else {
344 } else {
344 stream.next();
345 stream.next();
345 escaped = false;
346 escaped = false;
@@ -350,12 +351,52 b''
350 };
351 };
351 }
352 }
352
353
354 function tokenHereDoc(phrase, embed) {
355 return function (stream, state) {
356 if (stream.sol()) {
357 stream.eatSpace()
358 if (stream.match(phrase)) {
359 state.tokenize.pop();
360 return "string";
361 }
362 }
363
364 var escaped = false;
365 while (stream.peek()) {
366 if (!escaped) {
367 if (stream.match("{%", false)) {
368 state.tokenize.push(tokenMacro("%", "%"));
369 return "string";
370 }
371
372 if (stream.match("{{", false)) {
373 state.tokenize.push(tokenMacro("{", "}"));
374 return "string";
375 }
376
377 if (embed && stream.match("#{", false)) {
378 state.tokenize.push(tokenNest("#{", "}", "meta"));
379 return "string";
380 }
381
382 escaped = embed && stream.next() == "\\";
383 } else {
384 stream.next();
385 escaped = false;
386 }
387 }
388
389 return "string";
390 }
391 }
392
353 return {
393 return {
354 startState: function () {
394 startState: function () {
355 return {
395 return {
356 tokenize: [tokenBase],
396 tokenize: [tokenBase],
357 currentIndent: 0,
397 currentIndent: 0,
358 lastToken: null,
398 lastToken: null,
399 lastStyle: null,
359 blocks: []
400 blocks: []
360 };
401 };
361 },
402 },
@@ -366,6 +407,7 b''
366
407
367 if (style && style != "comment") {
408 if (style && style != "comment") {
368 state.lastToken = token;
409 state.lastToken = token;
410 state.lastStyle = style;
369 }
411 }
370
412
371 return style;
413 return style;
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -28,6 +28,7 b' CodeMirror.defineMode("css", function(co'
28 colorKeywords = parserConfig.colorKeywords || {},
28 colorKeywords = parserConfig.colorKeywords || {},
29 valueKeywords = parserConfig.valueKeywords || {},
29 valueKeywords = parserConfig.valueKeywords || {},
30 allowNested = parserConfig.allowNested,
30 allowNested = parserConfig.allowNested,
31 lineComment = parserConfig.lineComment,
31 supportsAtComponent = parserConfig.supportsAtComponent === true;
32 supportsAtComponent = parserConfig.supportsAtComponent === true;
32
33
33 var type, override;
34 var type, override;
@@ -62,7 +63,7 b' CodeMirror.defineMode("css", function(co'
62 if (/[\d.]/.test(stream.peek())) {
63 if (/[\d.]/.test(stream.peek())) {
63 stream.eatWhile(/[\w.%]/);
64 stream.eatWhile(/[\w.%]/);
64 return ret("number", "unit");
65 return ret("number", "unit");
65 } else if (stream.match(/^-[\w\\\-]+/)) {
66 } else if (stream.match(/^-[\w\\\-]*/)) {
66 stream.eatWhile(/[\w\\\-]/);
67 stream.eatWhile(/[\w\\\-]/);
67 if (stream.match(/^\s*:/, false))
68 if (stream.match(/^\s*:/, false))
68 return ret("variable-2", "variable-definition");
69 return ret("variable-2", "variable-definition");
@@ -76,12 +77,11 b' CodeMirror.defineMode("css", function(co'
76 return ret("qualifier", "qualifier");
77 return ret("qualifier", "qualifier");
77 } else if (/[:;{}\[\]\(\)]/.test(ch)) {
78 } else if (/[:;{}\[\]\(\)]/.test(ch)) {
78 return ret(null, ch);
79 return ret(null, ch);
79 } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
80 } else if (stream.match(/[\w-.]+(?=\()/)) {
80 (ch == "d" && stream.match("omain(")) ||
81 if (/^(url(-prefix)?|domain|regexp)$/.test(stream.current().toLowerCase())) {
81 (ch == "r" && stream.match("egexp("))) {
82 stream.backUp(1);
83 state.tokenize = tokenParenthesized;
82 state.tokenize = tokenParenthesized;
84 return ret("property", "word");
83 }
84 return ret("variable callee", "variable");
85 } else if (/[\w\\\-]/.test(ch)) {
85 } else if (/[\w\\\-]/.test(ch)) {
86 stream.eatWhile(/[\w\\\-]/);
86 stream.eatWhile(/[\w\\\-]/);
87 return ret("property", "word");
87 return ret("property", "word");
@@ -161,16 +161,16 b' CodeMirror.defineMode("css", function(co'
161 return pushContext(state, stream, "block");
161 return pushContext(state, stream, "block");
162 } else if (type == "}" && state.context.prev) {
162 } else if (type == "}" && state.context.prev) {
163 return popContext(state);
163 return popContext(state);
164 } else if (supportsAtComponent && /@component/.test(type)) {
164 } else if (supportsAtComponent && /@component/i.test(type)) {
165 return pushContext(state, stream, "atComponentBlock");
165 return pushContext(state, stream, "atComponentBlock");
166 } else if (/^@(-moz-)?document$/.test(type)) {
166 } else if (/^@(-moz-)?document$/i.test(type)) {
167 return pushContext(state, stream, "documentTypes");
167 return pushContext(state, stream, "documentTypes");
168 } else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
168 } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
169 return pushContext(state, stream, "atBlock");
169 return pushContext(state, stream, "atBlock");
170 } else if (/^@(font-face|counter-style)/.test(type)) {
170 } else if (/^@(font-face|counter-style)/i.test(type)) {
171 state.stateArg = type;
171 state.stateArg = type;
172 return "restricted_atBlock_before";
172 return "restricted_atBlock_before";
173 } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
173 } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
174 return "keyframes";
174 return "keyframes";
175 } else if (type && type.charAt(0) == "@") {
175 } else if (type && type.charAt(0) == "@") {
176 return pushContext(state, stream, "at");
176 return pushContext(state, stream, "at");
@@ -253,6 +253,8 b' CodeMirror.defineMode("css", function(co'
253 };
253 };
254
254
255 states.pseudo = function(type, stream, state) {
255 states.pseudo = function(type, stream, state) {
256 if (type == "meta") return "pseudo";
257
256 if (type == "word") {
258 if (type == "word") {
257 override = "variable-3";
259 override = "variable-3";
258 return state.context.type;
260 return state.context.type;
@@ -380,6 +382,7 b' CodeMirror.defineMode("css", function(co'
380 style = style[0];
382 style = style[0];
381 }
383 }
382 override = style;
384 override = style;
385 if (type != "comment")
383 state.state = states[state.state](type, stream, state);
386 state.state = states[state.state](type, stream, state);
384 return override;
387 return override;
385 },
388 },
@@ -398,7 +401,6 b' CodeMirror.defineMode("css", function(co'
398 ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
401 ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
399 // Dedent relative to current context.
402 // Dedent relative to current context.
400 indent = Math.max(0, cx.indent - indentUnit);
403 indent = Math.max(0, cx.indent - indentUnit);
401 cx = cx.prev;
402 }
404 }
403 }
405 }
404 return indent;
406 return indent;
@@ -407,6 +409,8 b' CodeMirror.defineMode("css", function(co'
407 electricChars: "}",
409 electricChars: "}",
408 blockCommentStart: "/*",
410 blockCommentStart: "/*",
409 blockCommentEnd: "*/",
411 blockCommentEnd: "*/",
412 blockCommentContinue: " * ",
413 lineComment: lineComment,
410 fold: "brace"
414 fold: "brace"
411 };
415 };
412 });
416 });
@@ -414,7 +418,7 b' CodeMirror.defineMode("css", function(co'
414 function keySet(array) {
418 function keySet(array) {
415 var keys = {};
419 var keys = {};
416 for (var i = 0; i < array.length; ++i) {
420 for (var i = 0; i < array.length; ++i) {
417 keys[array[i]] = true;
421 keys[array[i].toLowerCase()] = true;
418 }
422 }
419 return keys;
423 return keys;
420 }
424 }
@@ -468,7 +472,7 b' CodeMirror.defineMode("css", function(co'
468 "border-top-left-radius", "border-top-right-radius", "border-top-style",
472 "border-top-left-radius", "border-top-right-radius", "border-top-style",
469 "border-top-width", "border-width", "bottom", "box-decoration-break",
473 "border-top-width", "border-width", "bottom", "box-decoration-break",
470 "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
474 "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
471 "caption-side", "clear", "clip", "color", "color-profile", "column-count",
475 "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
472 "column-fill", "column-gap", "column-rule", "column-rule-color",
476 "column-fill", "column-gap", "column-rule", "column-rule-color",
473 "column-rule-style", "column-rule-width", "column-span", "column-width",
477 "column-rule-style", "column-rule-width", "column-span", "column-width",
474 "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
478 "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
@@ -484,19 +488,19 b' CodeMirror.defineMode("css", function(co'
484 "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
488 "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
485 "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
489 "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
486 "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
490 "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
487 "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end",
491 "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
488 "grid-column-start", "grid-row", "grid-row-end", "grid-row-start",
492 "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
489 "grid-template", "grid-template-areas", "grid-template-columns",
493 "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
490 "grid-template-rows", "hanging-punctuation", "height", "hyphens",
494 "grid-template-rows", "hanging-punctuation", "height", "hyphens",
491 "icon", "image-orientation", "image-rendering", "image-resolution",
495 "icon", "image-orientation", "image-rendering", "image-resolution",
492 "inline-box-align", "justify-content", "left", "letter-spacing",
496 "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
493 "line-break", "line-height", "line-stacking", "line-stacking-ruby",
497 "line-break", "line-height", "line-stacking", "line-stacking-ruby",
494 "line-stacking-shift", "line-stacking-strategy", "list-style",
498 "line-stacking-shift", "line-stacking-strategy", "list-style",
495 "list-style-image", "list-style-position", "list-style-type", "margin",
499 "list-style-image", "list-style-position", "list-style-type", "margin",
496 "margin-bottom", "margin-left", "margin-right", "margin-top",
500 "margin-bottom", "margin-left", "margin-right", "margin-top",
497 "marker-offset", "marks", "marquee-direction", "marquee-loop",
501 "marks", "marquee-direction", "marquee-loop",
498 "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
502 "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
499 "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
503 "max-width", "min-height", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index",
500 "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
504 "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
501 "opacity", "order", "orphans", "outline",
505 "opacity", "order", "orphans", "outline",
502 "outline-color", "outline-offset", "outline-style", "outline-width",
506 "outline-color", "outline-offset", "outline-style", "outline-width",
@@ -504,7 +508,7 b' CodeMirror.defineMode("css", function(co'
504 "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
508 "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
505 "page", "page-break-after", "page-break-before", "page-break-inside",
509 "page", "page-break-after", "page-break-before", "page-break-inside",
506 "page-policy", "pause", "pause-after", "pause-before", "perspective",
510 "page-policy", "pause", "pause-after", "pause-before", "perspective",
507 "perspective-origin", "pitch", "pitch-range", "play-during", "position",
511 "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
508 "presentation-level", "punctuation-trim", "quotes", "region-break-after",
512 "presentation-level", "punctuation-trim", "quotes", "region-break-after",
509 "region-break-before", "region-break-inside", "region-fragment",
513 "region-break-before", "region-break-inside", "region-fragment",
510 "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
514 "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
@@ -522,9 +526,9 b' CodeMirror.defineMode("css", function(co'
522 "text-wrap", "top", "transform", "transform-origin", "transform-style",
526 "text-wrap", "top", "transform", "transform-origin", "transform-style",
523 "transition", "transition-delay", "transition-duration",
527 "transition", "transition-delay", "transition-duration",
524 "transition-property", "transition-timing-function", "unicode-bidi",
528 "transition-property", "transition-timing-function", "unicode-bidi",
525 "vertical-align", "visibility", "voice-balance", "voice-duration",
529 "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
526 "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
530 "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
527 "voice-volume", "volume", "white-space", "widows", "width", "word-break",
531 "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
528 "word-spacing", "word-wrap", "z-index",
532 "word-spacing", "word-wrap", "z-index",
529 // SVG-specific
533 // SVG-specific
530 "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
534 "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
@@ -589,7 +593,7 b' CodeMirror.defineMode("css", function(co'
589 "above", "absolute", "activeborder", "additive", "activecaption", "afar",
593 "above", "absolute", "activeborder", "additive", "activecaption", "afar",
590 "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
594 "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
591 "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
595 "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
592 "arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page",
596 "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
593 "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
597 "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
594 "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
598 "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
595 "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
599 "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
@@ -598,10 +602,10 b' CodeMirror.defineMode("css", function(co'
598 "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
602 "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
599 "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
603 "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
600 "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
604 "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
601 "compact", "condensed", "contain", "content",
605 "compact", "condensed", "contain", "content", "contents",
602 "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
606 "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
603 "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
607 "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
604 "decimal-leading-zero", "default", "default-button", "destination-atop",
608 "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
605 "destination-in", "destination-out", "destination-over", "devanagari", "difference",
609 "destination-in", "destination-out", "destination-over", "devanagari", "difference",
606 "disc", "discard", "disclosure-closed", "disclosure-open", "document",
610 "disc", "discard", "disclosure-closed", "disclosure-open", "document",
607 "dot-dash", "dot-dot-dash",
611 "dot-dash", "dot-dot-dash",
@@ -615,13 +619,13 b' CodeMirror.defineMode("css", function(co'
615 "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
619 "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
616 "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
620 "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
617 "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
621 "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
618 "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
622 "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
619 "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
623 "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
620 "help", "hidden", "hide", "higher", "highlight", "highlighttext",
624 "help", "hidden", "hide", "higher", "highlight", "highlighttext",
621 "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
625 "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
622 "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
626 "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
623 "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
627 "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
624 "inline-block", "inline-flex", "inline-table", "inset", "inside", "intrinsic", "invert",
628 "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
625 "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
629 "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
626 "katakana", "katakana-iroha", "keep-all", "khmer",
630 "katakana", "katakana-iroha", "keep-all", "khmer",
627 "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
631 "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
@@ -641,7 +645,7 b' CodeMirror.defineMode("css", function(co'
641 "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
645 "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
642 "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
646 "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
643 "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
647 "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
644 "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
648 "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
645 "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
649 "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
646 "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
650 "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
647 "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
651 "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
@@ -653,17 +657,17 b' CodeMirror.defineMode("css", function(co'
653 "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
657 "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
654 "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
658 "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
655 "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
659 "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
656 "scroll", "scrollbar", "se-resize", "searchfield",
660 "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
657 "searchfield-cancel-button", "searchfield-decoration",
661 "searchfield-cancel-button", "searchfield-decoration",
658 "searchfield-results-button", "searchfield-results-decoration",
662 "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
659 "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
663 "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
660 "simp-chinese-formal", "simp-chinese-informal", "single",
664 "simp-chinese-formal", "simp-chinese-informal", "single",
661 "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
665 "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
662 "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
666 "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
663 "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
667 "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
664 "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "spell-out", "square",
668 "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
665 "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
669 "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
666 "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table",
670 "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
667 "table-caption", "table-cell", "table-column", "table-column-group",
671 "table-caption", "table-cell", "table-column", "table-column-group",
668 "table-footer-group", "table-header-group", "table-row", "table-row-group",
672 "table-footer-group", "table-header-group", "table-row", "table-row-group",
669 "tamil",
673 "tamil",
@@ -671,9 +675,9 b' CodeMirror.defineMode("css", function(co'
671 "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
675 "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
672 "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
676 "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
673 "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
677 "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
674 "trad-chinese-formal", "trad-chinese-informal",
678 "trad-chinese-formal", "trad-chinese-informal", "transform",
675 "translate", "translate3d", "translateX", "translateY", "translateZ",
679 "translate", "translate3d", "translateX", "translateY", "translateZ",
676 "transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
680 "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
677 "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
681 "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
678 "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
682 "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
679 "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
683 "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
@@ -730,6 +734,7 b' CodeMirror.defineMode("css", function(co'
730 valueKeywords: valueKeywords,
734 valueKeywords: valueKeywords,
731 fontProperties: fontProperties,
735 fontProperties: fontProperties,
732 allowNested: true,
736 allowNested: true,
737 lineComment: "//",
733 tokenHooks: {
738 tokenHooks: {
734 "/": function(stream, state) {
739 "/": function(stream, state) {
735 if (stream.eat("/")) {
740 if (stream.eat("/")) {
@@ -743,8 +748,8 b' CodeMirror.defineMode("css", function(co'
743 }
748 }
744 },
749 },
745 ":": function(stream) {
750 ":": function(stream) {
746 if (stream.match(/\s*\{/))
751 if (stream.match(/\s*\{/, false))
747 return [null, "{"];
752 return [null, null]
748 return false;
753 return false;
749 },
754 },
750 "$": function(stream) {
755 "$": function(stream) {
@@ -772,6 +777,7 b' CodeMirror.defineMode("css", function(co'
772 valueKeywords: valueKeywords,
777 valueKeywords: valueKeywords,
773 fontProperties: fontProperties,
778 fontProperties: fontProperties,
774 allowNested: true,
779 allowNested: true,
780 lineComment: "//",
775 tokenHooks: {
781 tokenHooks: {
776 "/": function(stream, state) {
782 "/": function(stream, state) {
777 if (stream.eat("/")) {
783 if (stream.eat("/")) {
@@ -786,7 +792,7 b' CodeMirror.defineMode("css", function(co'
786 },
792 },
787 "@": function(stream) {
793 "@": function(stream) {
788 if (stream.eat("{")) return [null, "interpolation"];
794 if (stream.eat("{")) return [null, "interpolation"];
789 if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
795 if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
790 stream.eatWhile(/[\w\\\-]/);
796 stream.eatWhile(/[\w\\\-]/);
791 if (stream.match(/^\s*:/, false))
797 if (stream.match(/^\s*:/, false))
792 return ["variable-2", "variable-definition"];
798 return ["variable-2", "variable-definition"];
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // By the Neo4j Team and contributors.
4 // By the Neo4j Team and contributors.
5 // https://github.com/neo4j-contrib/CodeMirror
5 // https://github.com/neo4j-contrib/CodeMirror
@@ -20,8 +20,12 b''
20 CodeMirror.defineMode("cypher", function(config) {
20 CodeMirror.defineMode("cypher", function(config) {
21 var tokenBase = function(stream/*, state*/) {
21 var tokenBase = function(stream/*, state*/) {
22 var ch = stream.next();
22 var ch = stream.next();
23 if (ch === "\"" || ch === "'") {
23 if (ch ==='"') {
24 stream.match(/.+?["']/);
24 stream.match(/.*?"/);
25 return "string";
26 }
27 if (ch === "'") {
28 stream.match(/.*?'/);
25 return "string";
29 return "string";
26 }
30 }
27 if (/[{}\(\),\.;\[\]]/.test(ch)) {
31 if (/[{}\(\),\.;\[\]]/.test(ch)) {
@@ -62,7 +66,7 b''
62 var curPunc;
66 var curPunc;
63 var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "reverse", "right", "round", "rtrim", "shortestPath", "sign", "sin", "size", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "toString", "trim", "type", "upper"]);
67 var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "reverse", "right", "round", "rtrim", "shortestPath", "sign", "sin", "size", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "toString", "trim", "type", "upper"]);
64 var preds = wordRegexp(["all", "and", "any", "contains", "exists", "has", "in", "none", "not", "or", "single", "xor"]);
68 var preds = wordRegexp(["all", "and", "any", "contains", "exists", "has", "in", "none", "not", "or", "single", "xor"]);
65 var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]);
69 var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with", "call", "yield"]);
66 var operatorChars = /[*+\-<>=&|~%^]/;
70 var operatorChars = /[*+\-<>=&|~%^]/;
67
71
68 return {
72 return {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -44,7 +44,7 b' CodeMirror.defineMode("d", function(conf'
44 }
44 }
45 if (ch == "/") {
45 if (ch == "/") {
46 if (stream.eat("+")) {
46 if (stream.eat("+")) {
47 state.tokenize = tokenComment;
47 state.tokenize = tokenNestedComment;
48 return tokenNestedComment(stream, state);
48 return tokenNestedComment(stream, state);
49 }
49 }
50 if (stream.eat("*")) {
50 if (stream.eat("*")) {
@@ -182,7 +182,12 b' CodeMirror.defineMode("d", function(conf'
182 else return ctx.indented + (closing ? 0 : indentUnit);
182 else return ctx.indented + (closing ? 0 : indentUnit);
183 },
183 },
184
184
185 electricChars: "{}"
185 electricChars: "{}",
186 blockCommentStart: "/*",
187 blockCommentEnd: "*/",
188 blockCommentContinue: " * ",
189 lineComment: "//",
190 fold: "brace"
186 };
191 };
187 });
192 });
188
193
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -12,10 +12,10 b''
12 "use strict";
12 "use strict";
13
13
14 var keywords = ("this super static final const abstract class extends external factory " +
14 var keywords = ("this super static final const abstract class extends external factory " +
15 "implements get native operator set typedef with enum throw rethrow " +
15 "implements mixin get native set typedef with enum throw rethrow " +
16 "assert break case continue default in return new deferred async await " +
16 "assert break case continue default in return new deferred async await covariant " +
17 "try catch finally do else for if switch while import library export " +
17 "try catch finally do else for if switch while import library export " +
18 "part of show hide is as").split(" ");
18 "part of show hide is as extension on").split(" ");
19 var blockKeywords = "try catch finally do else for if switch while".split(" ");
19 var blockKeywords = "try catch finally do else for if switch while".split(" ");
20 var atoms = "true false null".split(" ");
20 var atoms = "true false null".split(" ");
21 var builtins = "void bool num int double dynamic var String".split(" ");
21 var builtins = "void bool num int double dynamic var String".split(" ");
@@ -72,6 +72,21 b''
72 return null;
72 return null;
73 }
73 }
74 return false;
74 return false;
75 },
76
77 "/": function(stream, state) {
78 if (!stream.eat("*")) return false
79 state.tokenize = tokenNestedComment(1)
80 return state.tokenize(stream, state)
81 },
82 token: function(stream, _, style) {
83 if (style == "variable") {
84 // Assume uppercase symbols are classes using variable-2
85 var isUpper = RegExp('^[_$]*[A-Z][a-zA-Z0-9_$]*$','g');
86 if (isUpper.test(stream.current())) {
87 return 'variable-2';
88 }
89 }
75 }
90 }
76 }
91 }
77 });
92 });
@@ -121,6 +136,27 b''
121 return "variable";
136 return "variable";
122 }
137 }
123
138
139 function tokenNestedComment(depth) {
140 return function (stream, state) {
141 var ch
142 while (ch = stream.next()) {
143 if (ch == "*" && stream.eat("/")) {
144 if (depth == 1) {
145 state.tokenize = null
146 break
147 } else {
148 state.tokenize = tokenNestedComment(depth - 1)
149 return state.tokenize(stream, state)
150 }
151 } else if (ch == "/" && stream.eat("*")) {
152 state.tokenize = tokenNestedComment(depth + 1)
153 return state.tokenize(stream, state)
154 }
155 }
156 return "comment"
157 }
158 }
159
124 CodeMirror.registerHelper("hintWords", "application/dart", keywords.concat(atoms).concat(builtins));
160 CodeMirror.registerHelper("hintWords", "application/dart", keywords.concat(atoms).concat(builtins));
125
161
126 // This is needed to make loading through meta.js work.
162 // This is needed to make loading through meta.js work.
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -66,11 +66,11 b''
66 }
66 }
67
67
68 // A string can be included in either single or double quotes (this is
68 // A string can be included in either single or double quotes (this is
69 // the delimeter). Mark everything as a string until the start delimeter
69 // the delimiter). Mark everything as a string until the start delimiter
70 // occurs again.
70 // occurs again.
71 function inString (delimeter, previousTokenizer) {
71 function inString (delimiter, previousTokenizer) {
72 return function (stream, state) {
72 return function (stream, state) {
73 if (!state.escapeNext && stream.eat(delimeter)) {
73 if (!state.escapeNext && stream.eat(delimiter)) {
74 state.tokenize = previousTokenizer;
74 state.tokenize = previousTokenizer;
75 } else {
75 } else {
76 if (state.escapeNext) {
76 if (state.escapeNext) {
@@ -80,7 +80,7 b''
80 var ch = stream.next();
80 var ch = stream.next();
81
81
82 // Take into account the backslash for escaping characters, such as
82 // Take into account the backslash for escaping characters, such as
83 // the string delimeter.
83 // the string delimiter.
84 if (ch == "\\") {
84 if (ch == "\\") {
85 state.escapeNext = true;
85 state.escapeNext = true;
86 }
86 }
@@ -100,7 +100,7 b''
100 return "null";
100 return "null";
101 }
101 }
102
102
103 // Dot folowed by a non-word character should be considered an error.
103 // Dot followed by a non-word character should be considered an error.
104 if (stream.match(/\.\W+/)) {
104 if (stream.match(/\.\W+/)) {
105 return "error";
105 return "error";
106 } else if (stream.eat(".")) {
106 } else if (stream.eat(".")) {
@@ -119,7 +119,7 b''
119 return "null";
119 return "null";
120 }
120 }
121
121
122 // Pipe folowed by a non-word character should be considered an error.
122 // Pipe followed by a non-word character should be considered an error.
123 if (stream.match(/\.\W+/)) {
123 if (stream.match(/\.\W+/)) {
124 return "error";
124 return "error";
125 } else if (stream.eat("|")) {
125 } else if (stream.eat("|")) {
@@ -199,7 +199,7 b''
199 return "null";
199 return "null";
200 }
200 }
201
201
202 // Dot folowed by a non-word character should be considered an error.
202 // Dot followed by a non-word character should be considered an error.
203 if (stream.match(/\.\W+/)) {
203 if (stream.match(/\.\W+/)) {
204 return "error";
204 return "error";
205 } else if (stream.eat(".")) {
205 } else if (stream.eat(".")) {
@@ -218,7 +218,7 b''
218 return "null";
218 return "null";
219 }
219 }
220
220
221 // Pipe folowed by a non-word character should be considered an error.
221 // Pipe followed by a non-word character should be considered an error.
222 if (stream.match(/\.\W+/)) {
222 if (stream.match(/\.\W+/)) {
223 return "error";
223 return "error";
224 } else if (stream.eat("|")) {
224 } else if (stream.eat("|")) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -11,30 +11,64 b''
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 var from = "from";
15 var fromRegex = new RegExp("^(\\s*)\\b(" + from + ")\\b", "i");
16
17 var shells = ["run", "cmd", "entrypoint", "shell"];
18 var shellsAsArrayRegex = new RegExp("^(\\s*)(" + shells.join('|') + ")(\\s+\\[)", "i");
19
20 var expose = "expose";
21 var exposeRegex = new RegExp("^(\\s*)(" + expose + ")(\\s+)", "i");
22
23 var others = [
24 "arg", "from", "maintainer", "label", "env",
25 "add", "copy", "volume", "user",
26 "workdir", "onbuild", "stopsignal", "healthcheck", "shell"
27 ];
28
14 // Collect all Dockerfile directives
29 // Collect all Dockerfile directives
15 var instructions = ["from", "maintainer", "run", "cmd", "expose", "env",
30 var instructions = [from, expose].concat(shells).concat(others),
16 "add", "copy", "entrypoint", "volume", "user",
17 "workdir", "onbuild"],
18 instructionRegex = "(" + instructions.join('|') + ")",
31 instructionRegex = "(" + instructions.join('|') + ")",
19 instructionOnlyLine = new RegExp(instructionRegex + "\\s*$", "i"),
32 instructionOnlyLine = new RegExp("^(\\s*)" + instructionRegex + "(\\s*)(#.*)?$", "i"),
20 instructionWithArguments = new RegExp(instructionRegex + "(\\s+)", "i");
33 instructionWithArguments = new RegExp("^(\\s*)" + instructionRegex + "(\\s+)", "i");
21
34
22 CodeMirror.defineSimpleMode("dockerfile", {
35 CodeMirror.defineSimpleMode("dockerfile", {
23 start: [
36 start: [
24 // Block comment: This is a line starting with a comment
37 // Block comment: This is a line starting with a comment
25 {
38 {
26 regex: /#.*$/,
39 regex: /^\s*#.*$/,
40 sol: true,
27 token: "comment"
41 token: "comment"
28 },
42 },
43 {
44 regex: fromRegex,
45 token: [null, "keyword"],
46 sol: true,
47 next: "from"
48 },
29 // Highlight an instruction without any arguments (for convenience)
49 // Highlight an instruction without any arguments (for convenience)
30 {
50 {
31 regex: instructionOnlyLine,
51 regex: instructionOnlyLine,
32 token: "variable-2"
52 token: [null, "keyword", null, "error"],
53 sol: true
54 },
55 {
56 regex: shellsAsArrayRegex,
57 token: [null, "keyword", null],
58 sol: true,
59 next: "array"
60 },
61 {
62 regex: exposeRegex,
63 token: [null, "keyword", null],
64 sol: true,
65 next: "expose"
33 },
66 },
34 // Highlight an instruction followed by arguments
67 // Highlight an instruction followed by arguments
35 {
68 {
36 regex: instructionWithArguments,
69 regex: instructionWithArguments,
37 token: ["variable-2", null],
70 token: [null, "keyword", null],
71 sol: true,
38 next: "arguments"
72 next: "arguments"
39 },
73 },
40 {
74 {
@@ -42,27 +76,125 b''
42 token: null
76 token: null
43 }
77 }
44 ],
78 ],
45 arguments: [
79 from: [
80 {
81 regex: /\s*$/,
82 token: null,
83 next: "start"
84 },
46 {
85 {
47 // Line comment without instruction arguments is an error
86 // Line comment without instruction arguments is an error
48 regex: /#.*$/,
87 regex: /(\s*)(#.*)$/,
49 token: "error",
88 token: [null, "error"],
50 next: "start"
89 next: "start"
51 },
90 },
52 {
91 {
53 regex: /[^#]+\\$/,
92 regex: /(\s*\S+\s+)(as)/i,
54 token: null
93 token: [null, "keyword"],
94 next: "start"
95 },
96 // Fail safe return to start
97 {
98 token: null,
99 next: "start"
100 }
101 ],
102 single: [
103 {
104 regex: /(?:[^\\']|\\.)/,
105 token: "string"
55 },
106 },
56 {
107 {
57 // Match everything except for the inline comment
108 regex: /'/,
58 regex: /[^#]+/,
109 token: "string",
110 pop: true
111 }
112 ],
113 double: [
114 {
115 regex: /(?:[^\\"]|\\.)/,
116 token: "string"
117 },
118 {
119 regex: /"/,
120 token: "string",
121 pop: true
122 }
123 ],
124 array: [
125 {
126 regex: /\]/,
59 token: null,
127 token: null,
60 next: "start"
128 next: "start"
61 },
129 },
62 {
130 {
63 regex: /$/,
131 regex: /"(?:[^\\"]|\\.)*"?/,
132 token: "string"
133 }
134 ],
135 expose: [
136 {
137 regex: /\d+$/,
138 token: "number",
139 next: "start"
140 },
141 {
142 regex: /[^\d]+$/,
143 token: null,
144 next: "start"
145 },
146 {
147 regex: /\d+/,
148 token: "number"
149 },
150 {
151 regex: /[^\d]+/,
152 token: null
153 },
154 // Fail safe return to start
155 {
64 token: null,
156 token: null,
65 next: "start"
157 next: "start"
158 }
159 ],
160 arguments: [
161 {
162 regex: /^\s*#.*$/,
163 sol: true,
164 token: "comment"
165 },
166 {
167 regex: /"(?:[^\\"]|\\.)*"?$/,
168 token: "string",
169 next: "start"
170 },
171 {
172 regex: /"/,
173 token: "string",
174 push: "double"
175 },
176 {
177 regex: /'(?:[^\\']|\\.)*'?$/,
178 token: "string",
179 next: "start"
180 },
181 {
182 regex: /'/,
183 token: "string",
184 push: "single"
185 },
186 {
187 regex: /[^#"']+[\\`]$/,
188 token: null
189 },
190 {
191 regex: /[^#"']+$/,
192 token: null,
193 next: "start"
194 },
195 {
196 regex: /[^#"']+/,
197 token: null
66 },
198 },
67 // Fail safe return to start
199 // Fail safe return to start
68 {
200 {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /*
4 /*
5 DTD mode
5 DTD mode
@@ -114,17 +114,17 b' CodeMirror.defineMode("dtd", function(co'
114
114
115 if( textAfter.match(/\]\s+|\]/) )n=n-1;
115 if( textAfter.match(/\]\s+|\]/) )n=n-1;
116 else if(textAfter.substr(textAfter.length-1, textAfter.length) === ">"){
116 else if(textAfter.substr(textAfter.length-1, textAfter.length) === ">"){
117 if(textAfter.substr(0,1) === "<")n;
117 if(textAfter.substr(0,1) === "<") {}
118 else if( type == "doindent" && textAfter.length > 1 )n;
118 else if( type == "doindent" && textAfter.length > 1 ) {}
119 else if( type == "doindent")n--;
119 else if( type == "doindent")n--;
120 else if( type == ">" && textAfter.length > 1)n;
120 else if( type == ">" && textAfter.length > 1) {}
121 else if( type == "tag" && textAfter !== ">")n;
121 else if( type == "tag" && textAfter !== ">") {}
122 else if( type == "tag" && state.stack[state.stack.length-1] == "rule")n--;
122 else if( type == "tag" && state.stack[state.stack.length-1] == "rule")n--;
123 else if( type == "tag")n++;
123 else if( type == "tag")n++;
124 else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule" && type === ">")n--;
124 else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule" && type === ">")n--;
125 else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule")n;
125 else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule") {}
126 else if( textAfter.substr(0,1) !== "<" && textAfter.substr(0,1) === ">" )n=n-1;
126 else if( textAfter.substr(0,1) !== "<" && textAfter.substr(0,1) === ">" )n=n-1;
127 else if( textAfter === ">")n;
127 else if( textAfter === ">") {}
128 else n=n-1;
128 else n=n-1;
129 //over rule them all
129 //over rule them all
130 if(type == null || type == "]")n--;
130 if(type == null || type == "]")n--;
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -11,6 +11,14 b''
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 function forEach(arr, f) {
15 for (var i = 0; i < arr.length; i++) f(arr[i], i)
16 }
17 function some(arr, f) {
18 for (var i = 0; i < arr.length; i++) if (f(arr[i], i)) return true
19 return false
20 }
21
14 CodeMirror.defineMode("dylan", function(_config) {
22 CodeMirror.defineMode("dylan", function(_config) {
15 // Words
23 // Words
16 var words = {
24 var words = {
@@ -136,13 +144,13 b' CodeMirror.defineMode("dylan", function('
136 var wordLookup = {};
144 var wordLookup = {};
137 var styleLookup = {};
145 var styleLookup = {};
138
146
139 [
147 forEach([
140 "keyword",
148 "keyword",
141 "definition",
149 "definition",
142 "simpleDefinition",
150 "simpleDefinition",
143 "signalingCalls"
151 "signalingCalls"
144 ].forEach(function(type) {
152 ], function(type) {
145 words[type].forEach(function(word) {
153 forEach(words[type], function(word) {
146 wordLookup[word] = type;
154 wordLookup[word] = type;
147 styleLookup[word] = styles[type];
155 styleLookup[word] = styles[type];
148 });
156 });
@@ -169,16 +177,17 b' CodeMirror.defineMode("dylan", function('
169 } else if (stream.eat("/")) {
177 } else if (stream.eat("/")) {
170 stream.skipToEnd();
178 stream.skipToEnd();
171 return "comment";
179 return "comment";
172 } else {
173 stream.skipTo(" ");
174 return "operator";
175 }
180 }
181 stream.backUp(1);
176 }
182 }
177 // Decimal
183 // Decimal
178 else if (/\d/.test(ch)) {
184 else if (/[+\-\d\.]/.test(ch)) {
179 stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
185 if (stream.match(/^[+-]?[0-9]*\.[0-9]*([esdx][+-]?[0-9]+)?/i) ||
186 stream.match(/^[+-]?[0-9]+([esdx][+-]?[0-9]+)/i) ||
187 stream.match(/^[+-]?\d+/)) {
180 return "number";
188 return "number";
181 }
189 }
190 }
182 // Hash
191 // Hash
183 else if (ch == "#") {
192 else if (ch == "#") {
184 stream.next();
193 stream.next();
@@ -186,7 +195,7 b' CodeMirror.defineMode("dylan", function('
186 ch = stream.peek();
195 ch = stream.peek();
187 if (ch == '"') {
196 if (ch == '"') {
188 stream.next();
197 stream.next();
189 return chain(stream, state, tokenString('"', "string-2"));
198 return chain(stream, state, tokenString('"', "string"));
190 }
199 }
191 // Binary number
200 // Binary number
192 else if (ch == "b") {
201 else if (ch == "b") {
@@ -206,29 +215,73 b' CodeMirror.defineMode("dylan", function('
206 stream.eatWhile(/[0-7]/);
215 stream.eatWhile(/[0-7]/);
207 return "number";
216 return "number";
208 }
217 }
218 // Token concatenation in macros
219 else if (ch == '#') {
220 stream.next();
221 return "punctuation";
222 }
223 // Sequence literals
224 else if ((ch == '[') || (ch == '(')) {
225 stream.next();
226 return "bracket";
209 // Hash symbol
227 // Hash symbol
210 else {
228 } else if (stream.match(/f|t|all-keys|include|key|next|rest/i)) {
229 return "atom";
230 } else {
211 stream.eatWhile(/[-a-zA-Z]/);
231 stream.eatWhile(/[-a-zA-Z]/);
212 return "keyword";
232 return "error";
233 }
234 } else if (ch == "~") {
235 stream.next();
236 ch = stream.peek();
237 if (ch == "=") {
238 stream.next();
239 ch = stream.peek();
240 if (ch == "=") {
241 stream.next();
242 return "operator";
243 }
244 return "operator";
213 }
245 }
246 return "operator";
247 } else if (ch == ":") {
248 stream.next();
249 ch = stream.peek();
250 if (ch == "=") {
251 stream.next();
252 return "operator";
253 } else if (ch == ":") {
254 stream.next();
255 return "punctuation";
256 }
257 } else if ("[](){}".indexOf(ch) != -1) {
258 stream.next();
259 return "bracket";
260 } else if (".,".indexOf(ch) != -1) {
261 stream.next();
262 return "punctuation";
214 } else if (stream.match("end")) {
263 } else if (stream.match("end")) {
215 return "keyword";
264 return "keyword";
216 }
265 }
217 for (var name in patterns) {
266 for (var name in patterns) {
218 if (patterns.hasOwnProperty(name)) {
267 if (patterns.hasOwnProperty(name)) {
219 var pattern = patterns[name];
268 var pattern = patterns[name];
220 if ((pattern instanceof Array && pattern.some(function(p) {
269 if ((pattern instanceof Array && some(pattern, function(p) {
221 return stream.match(p);
270 return stream.match(p);
222 })) || stream.match(pattern))
271 })) || stream.match(pattern))
223 return patternStyles[name];
272 return patternStyles[name];
224 }
273 }
225 }
274 }
275 if (/[+\-*\/^=<>&|]/.test(ch)) {
276 stream.next();
277 return "operator";
278 }
226 if (stream.match("define")) {
279 if (stream.match("define")) {
227 return "def";
280 return "def";
228 } else {
281 } else {
229 stream.eatWhile(/[\w\-]/);
282 stream.eatWhile(/[\w\-]/);
230 // Keyword
283 // Keyword
231 if (wordLookup[stream.current()]) {
284 if (wordLookup.hasOwnProperty(stream.current())) {
232 return styleLookup[stream.current()];
285 return styleLookup[stream.current()];
233 } else if (stream.current().match(symbol)) {
286 } else if (stream.current().match(symbol)) {
234 return "variable";
287 return "variable";
@@ -240,29 +293,37 b' CodeMirror.defineMode("dylan", function('
240 }
293 }
241
294
242 function tokenComment(stream, state) {
295 function tokenComment(stream, state) {
243 var maybeEnd = false,
296 var maybeEnd = false, maybeNested = false, nestedCount = 0, ch;
244 ch;
245 while ((ch = stream.next())) {
297 while ((ch = stream.next())) {
246 if (ch == "/" && maybeEnd) {
298 if (ch == "/" && maybeEnd) {
299 if (nestedCount > 0) {
300 nestedCount--;
301 } else {
247 state.tokenize = tokenBase;
302 state.tokenize = tokenBase;
248 break;
303 break;
249 }
304 }
305 } else if (ch == "*" && maybeNested) {
306 nestedCount++;
307 }
250 maybeEnd = (ch == "*");
308 maybeEnd = (ch == "*");
309 maybeNested = (ch == "/");
251 }
310 }
252 return "comment";
311 return "comment";
253 }
312 }
254
313
255 function tokenString(quote, style) {
314 function tokenString(quote, style) {
256 return function(stream, state) {
315 return function(stream, state) {
257 var next, end = false;
316 var escaped = false, next, end = false;
258 while ((next = stream.next()) != null) {
317 while ((next = stream.next()) != null) {
259 if (next == quote) {
318 if (next == quote && !escaped) {
260 end = true;
319 end = true;
261 break;
320 break;
262 }
321 }
322 escaped = !escaped && next == "\\";
263 }
323 }
264 if (end)
324 if (end || !escaped) {
265 state.tokenize = tokenBase;
325 state.tokenize = tokenBase;
326 }
266 return style;
327 return style;
267 };
328 };
268 }
329 }
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -94,7 +94,7 b''
94
94
95 if (bracesMode !== null && (state.braced || peek === "{")) {
95 if (bracesMode !== null && (state.braced || peek === "{")) {
96 if (state.localState === null)
96 if (state.localState === null)
97 state.localState = bracesMode.startState();
97 state.localState = CodeMirror.startState(bracesMode);
98
98
99 var token = bracesMode.token(stream, state.localState),
99 var token = bracesMode.token(stream, state.localState),
100 text = stream.current();
100 text = stream.current();
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -70,7 +70,7 b''
70 if (smallRE.test(ch)) {
70 if (smallRE.test(ch)) {
71 var isDef = source.pos === 1;
71 var isDef = source.pos === 1;
72 source.eatWhile(idRE);
72 source.eatWhile(idRE);
73 return isDef ? "variable-3" : "variable";
73 return isDef ? "type" : "variable";
74 }
74 }
75
75
76 if (digitRE.test(ch)) {
76 if (digitRE.test(ch)) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /*jshint unused:true, eqnull:true, curly:true, bitwise:true */
4 /*jshint unused:true, eqnull:true, curly:true, bitwise:true */
5 /*jshint undef:true, latedef:true, trailing:true */
5 /*jshint undef:true, latedef:true, trailing:true */
@@ -433,15 +433,16 b' CodeMirror.defineMode("erlang", function'
433 }
433 }
434
434
435 function maybe_drop_post(s) {
435 function maybe_drop_post(s) {
436 if (!s.length) return s
436 var last = s.length-1;
437 var last = s.length-1;
437
438
438 if (s[last].type === "dot") {
439 if (s[last].type === "dot") {
439 return [];
440 return [];
440 }
441 }
441 if (s[last].type === "fun" && s[last-1].token === "fun") {
442 if (last > 1 && s[last].type === "fun" && s[last-1].token === "fun") {
442 return s.slice(0,last-1);
443 return s.slice(0,last-1);
443 }
444 }
444 switch (s[s.length-1].token) {
445 switch (s[last].token) {
445 case "}": return d(s,{g:["{"]});
446 case "}": return d(s,{g:["{"]});
446 case "]": return d(s,{i:["["]});
447 case "]": return d(s,{i:["["]});
447 case ")": return d(s,{i:["("]});
448 case ")": return d(s,{i:["("]});
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Factor syntax highlight - simple mode
4 // Factor syntax highlight - simple mode
5 //
5 //
@@ -22,52 +22,54 b''
22 {regex: /#?!.*/, token: "comment"},
22 {regex: /#?!.*/, token: "comment"},
23 // strings """, multiline --> state
23 // strings """, multiline --> state
24 {regex: /"""/, token: "string", next: "string3"},
24 {regex: /"""/, token: "string", next: "string3"},
25 {regex: /"/, token: "string", next: "string"},
25 {regex: /(STRING:)(\s)/, token: ["keyword", null], next: "string2"},
26 {regex: /\S*?"/, token: "string", next: "string"},
26 // numbers: dec, hex, unicode, bin, fractional, complex
27 // numbers: dec, hex, unicode, bin, fractional, complex
27 {regex: /(?:[+-]?)(?:0x[\d,a-f]+)|(?:0o[0-7]+)|(?:0b[0,1]+)|(?:\d+.?\d*)/, token: "number"},
28 {regex: /(?:0x[\d,a-f]+)|(?:0o[0-7]+)|(?:0b[0,1]+)|(?:\-?\d+.?\d*)(?=\s)/, token: "number"},
28 //{regex: /[+-]?/} //fractional
29 //{regex: /[+-]?/} //fractional
29 // definition: defining word, defined word, etc
30 // definition: defining word, defined word, etc
30 {regex: /(\:)(\s+)(\S+)(\s+)(\()/, token: ["keyword", null, "def", null, "keyword"], next: "stack"},
31 {regex: /((?:GENERIC)|\:?\:)(\s+)(\S+)(\s+)(\()/, token: ["keyword", null, "def", null, "bracket"], next: "stack"},
32 // method definition: defining word, type, defined word, etc
33 {regex: /(M\:)(\s+)(\S+)(\s+)(\S+)/, token: ["keyword", null, "def", null, "tag"]},
31 // vocabulary using --> state
34 // vocabulary using --> state
32 {regex: /USING\:/, token: "keyword", next: "vocabulary"},
35 {regex: /USING\:/, token: "keyword", next: "vocabulary"},
33 // vocabulary definition/use
36 // vocabulary definition/use
34 {regex: /(USE\:|IN\:)(\s+)(\S+)/, token: ["keyword", null, "variable-2"]},
37 {regex: /(USE\:|IN\:)(\s+)(\S+)(?=\s|$)/, token: ["keyword", null, "tag"]},
35 // <constructors>
38 // definition: a defining word, defined word
36 {regex: /<\S+>/, token: "builtin"},
39 {regex: /(\S+\:)(\s+)(\S+)(?=\s|$)/, token: ["keyword", null, "def"]},
37 // "keywords", incl. ; t f . [ ] { } defining words
40 // "keywords", incl. ; t f . [ ] { } defining words
38 {regex: /;|t|f|if|\.|\[|\]|\{|\}|MAIN:/, token: "keyword"},
41 {regex: /(?:;|\\|t|f|if|loop|while|until|do|PRIVATE>|<PRIVATE|\.|\S*\[|\]|\S*\{|\})(?=\s|$)/, token: "keyword"},
42 // <constructors> and the like
43 {regex: /\S+[\)>\.\*\?]+(?=\s|$)/, token: "builtin"},
44 {regex: /[\)><]+\S+(?=\s|$)/, token: "builtin"},
45 // operators
46 {regex: /(?:[\+\-\=\/\*<>])(?=\s|$)/, token: "keyword"},
39 // any id (?)
47 // any id (?)
40 {regex: /\S+/, token: "variable"},
48 {regex: /\S+/, token: "variable"},
41
49 {regex: /\s+|./, token: null}
42 {
43 regex: /./,
44 token: null
45 }
46 ],
50 ],
47 vocabulary: [
51 vocabulary: [
48 {regex: /;/, token: "keyword", next: "start"},
52 {regex: /;/, token: "keyword", next: "start"},
49 {regex: /\S+/, token: "variable-2"},
53 {regex: /\S+/, token: "tag"},
50 {
54 {regex: /\s+|./, token: null}
51 regex: /./,
52 token: null
53 }
54 ],
55 ],
55 string: [
56 string: [
56 {regex: /(?:[^\\]|\\.)*?"/, token: "string", next: "start"},
57 {regex: /(?:[^\\]|\\.)*?"/, token: "string", next: "start"},
57 {regex: /.*/, token: "string"}
58 {regex: /.*/, token: "string"}
58 ],
59 ],
60 string2: [
61 {regex: /^;/, token: "keyword", next: "start"},
62 {regex: /.*/, token: "string"}
63 ],
59 string3: [
64 string3: [
60 {regex: /(?:[^\\]|\\.)*?"""/, token: "string", next: "start"},
65 {regex: /(?:[^\\]|\\.)*?"""/, token: "string", next: "start"},
61 {regex: /.*/, token: "string"}
66 {regex: /.*/, token: "string"}
62 ],
67 ],
63 stack: [
68 stack: [
64 {regex: /\)/, token: "meta", next: "start"},
69 {regex: /\)/, token: "bracket", next: "start"},
65 {regex: /--/, token: "meta"},
70 {regex: /--/, token: "bracket"},
66 {regex: /\S+/, token: "variable-3"},
71 {regex: /\S+/, token: "meta"},
67 {
72 {regex: /\s+|./, token: null}
68 regex: /./,
69 token: null
70 }
71 ],
73 ],
72 // The meta property contains global information about the mode. It
74 // The meta property contains global information about the mode. It
73 // can contain properties like lineComment, which are supported by
75 // can contain properties like lineComment, which are supported by
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Author: Aliaksei Chapyzhenka
4 // Author: Aliaksei Chapyzhenka
5
5
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -81,7 +81,7 b' CodeMirror.defineMode("gfm", function(co'
81 if (stream.sol() || state.ateSpace) {
81 if (stream.sol() || state.ateSpace) {
82 state.ateSpace = false;
82 state.ateSpace = false;
83 if (modeConfig.gitHubSpice !== false) {
83 if (modeConfig.gitHubSpice !== false) {
84 if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) {
84 if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?=.{0,6}\d)(?:[a-f0-9]{7,40}\b)/)) {
85 // User/Project@SHA
85 // User/Project@SHA
86 // User@SHA
86 // User@SHA
87 // SHA
87 // SHA
@@ -113,10 +113,9 b' CodeMirror.defineMode("gfm", function(co'
113 };
113 };
114
114
115 var markdownConfig = {
115 var markdownConfig = {
116 underscoresBreakWords: false,
117 taskLists: true,
116 taskLists: true,
118 fencedCodeBlocks: '```',
117 strikethrough: true,
119 strikethrough: true
118 emoji: true
120 };
119 };
121 for (var attr in modeConfig) {
120 for (var attr in modeConfig) {
122 markdownConfig[attr] = modeConfig[attr];
121 markdownConfig[attr] = modeConfig[attr];
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /*
4 /*
5 Gherkin mode - http://www.cukes.info/
5 Gherkin mode - http://www.cukes.info/
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -23,12 +23,13 b' CodeMirror.defineMode("go", function(con'
23 "bool":true, "byte":true, "complex64":true, "complex128":true,
23 "bool":true, "byte":true, "complex64":true, "complex128":true,
24 "float32":true, "float64":true, "int8":true, "int16":true, "int32":true,
24 "float32":true, "float64":true, "int8":true, "int16":true, "int32":true,
25 "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true,
25 "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true,
26 "uint64":true, "int":true, "uint":true, "uintptr":true
26 "uint64":true, "int":true, "uint":true, "uintptr":true, "error": true,
27 "rune":true
27 };
28 };
28
29
29 var atoms = {
30 var atoms = {
30 "true":true, "false":true, "iota":true, "nil":true, "append":true,
31 "true":true, "false":true, "iota":true, "nil":true, "append":true,
31 "cap":true, "close":true, "complex":true, "copy":true, "imag":true,
32 "cap":true, "close":true, "complex":true, "copy":true, "delete":true, "imag":true,
32 "len":true, "make":true, "new":true, "panic":true, "print":true,
33 "len":true, "make":true, "new":true, "panic":true, "print":true,
33 "println":true, "real":true, "recover":true
34 "println":true, "real":true, "recover":true
34 };
35 };
@@ -154,14 +155,14 b' CodeMirror.defineMode("go", function(con'
154 else if (curPunc == "[") pushContext(state, stream.column(), "]");
155 else if (curPunc == "[") pushContext(state, stream.column(), "]");
155 else if (curPunc == "(") pushContext(state, stream.column(), ")");
156 else if (curPunc == "(") pushContext(state, stream.column(), ")");
156 else if (curPunc == "case") ctx.type = "case";
157 else if (curPunc == "case") ctx.type = "case";
157 else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state);
158 else if (curPunc == "}" && ctx.type == "}") popContext(state);
158 else if (curPunc == ctx.type) popContext(state);
159 else if (curPunc == ctx.type) popContext(state);
159 state.startOfLine = false;
160 state.startOfLine = false;
160 return style;
161 return style;
161 },
162 },
162
163
163 indent: function(state, textAfter) {
164 indent: function(state, textAfter) {
164 if (state.tokenize != tokenBase && state.tokenize != null) return 0;
165 if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
165 var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
166 var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
166 if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) {
167 if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) {
167 state.context.type = "}";
168 state.context.type = "}";
@@ -173,6 +174,7 b' CodeMirror.defineMode("go", function(con'
173 },
174 },
174
175
175 electricChars: "{}):",
176 electricChars: "{}):",
177 closeBrackets: "()[]{}''\"\"``",
176 fold: "brace",
178 fold: "brace",
177 blockCommentStart: "/*",
179 blockCommentStart: "/*",
178 blockCommentEnd: "*/",
180 blockCommentEnd: "*/",
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -21,9 +21,9 b' CodeMirror.defineMode("groovy", function'
21 "abstract as assert boolean break byte case catch char class const continue def default " +
21 "abstract as assert boolean break byte case catch char class const continue def default " +
22 "do double else enum extends final finally float for goto if implements import in " +
22 "do double else enum extends final finally float for goto if implements import in " +
23 "instanceof int interface long native new package private protected public return " +
23 "instanceof int interface long native new package private protected public return " +
24 "short static strictfp super switch synchronized threadsafe throw throws transient " +
24 "short static strictfp super switch synchronized threadsafe throw throws trait transient " +
25 "try void volatile while");
25 "try void volatile while");
26 var blockKeywords = words("catch class do else finally for if switch try while enum interface def");
26 var blockKeywords = words("catch class def do else enum finally for if interface switch trait try while");
27 var standaloneKeywords = words("return break continue");
27 var standaloneKeywords = words("return break continue");
28 var atoms = words("null true false this");
28 var atoms = words("null true false this");
29
29
@@ -210,7 +210,7 b' CodeMirror.defineMode("groovy", function'
210 },
210 },
211
211
212 indent: function(state, textAfter) {
212 indent: function(state, textAfter) {
213 if (!state.tokenize[state.tokenize.length-1].isBase) return 0;
213 if (!state.tokenize[state.tokenize.length-1].isBase) return CodeMirror.Pass;
214 var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;
214 var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;
215 if (ctx.type == "statement" && !expectExpression(state.lastToken, true)) ctx = ctx.prev;
215 if (ctx.type == "statement" && !expectExpression(state.lastToken, true)) ctx = ctx.prev;
216 var closing = firstChar == ctx.type;
216 var closing = firstChar == ctx.type;
@@ -221,7 +221,10 b' CodeMirror.defineMode("groovy", function'
221
221
222 electricChars: "{}",
222 electricChars: "{}",
223 closeBrackets: {triples: "'\""},
223 closeBrackets: {triples: "'\""},
224 fold: "brace"
224 fold: "brace",
225 blockCommentStart: "/*",
226 blockCommentEnd: "*/",
227 lineComment: "//"
225 };
228 };
226 });
229 });
227
230
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -11,7 +11,7 b''
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 // full haml mode. This handled embeded ruby and html fragments too
14 // full haml mode. This handled embedded ruby and html fragments too
15 CodeMirror.defineMode("haml", function(config) {
15 CodeMirror.defineMode("haml", function(config) {
16 var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"});
16 var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"});
17 var rubyMode = CodeMirror.getMode(config, "ruby");
17 var rubyMode = CodeMirror.getMode(config, "ruby");
@@ -98,8 +98,8 b''
98 return {
98 return {
99 // default to html mode
99 // default to html mode
100 startState: function() {
100 startState: function() {
101 var htmlState = htmlMode.startState();
101 var htmlState = CodeMirror.startState(htmlMode);
102 var rubyState = rubyMode.startState();
102 var rubyState = CodeMirror.startState(rubyMode);
103 return {
103 return {
104 htmlState: htmlState,
104 htmlState: htmlState,
105 rubyState: rubyState,
105 rubyState: rubyState,
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -13,10 +13,14 b''
13
13
14 CodeMirror.defineSimpleMode("handlebars-tags", {
14 CodeMirror.defineSimpleMode("handlebars-tags", {
15 start: [
15 start: [
16 { regex: /\{\{\{/, push: "handlebars_raw", token: "tag" },
16 { regex: /\{\{!--/, push: "dash_comment", token: "comment" },
17 { regex: /\{\{!--/, push: "dash_comment", token: "comment" },
17 { regex: /\{\{!/, push: "comment", token: "comment" },
18 { regex: /\{\{!/, push: "comment", token: "comment" },
18 { regex: /\{\{/, push: "handlebars", token: "tag" }
19 { regex: /\{\{/, push: "handlebars", token: "tag" }
19 ],
20 ],
21 handlebars_raw: [
22 { regex: /\}\}\}/, pop: true, token: "tag" },
23 ],
20 handlebars: [
24 handlebars: [
21 { regex: /\}\}/, pop: true, token: "tag" },
25 { regex: /\}\}/, pop: true, token: "tag" },
22
26
@@ -46,7 +50,11 b''
46 comment: [
50 comment: [
47 { regex: /\}\}/, pop: true, token: "comment" },
51 { regex: /\}\}/, pop: true, token: "comment" },
48 { regex: /./, token: "comment" }
52 { regex: /./, token: "comment" }
49 ]
53 ],
54 meta: {
55 blockCommentStart: "{{--",
56 blockCommentEnd: "--}}"
57 }
50 });
58 });
51
59
52 CodeMirror.defineMode("handlebars", function(config, parserConfig) {
60 CodeMirror.defineMode("handlebars", function(config, parserConfig) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function (mod) {
4 (function (mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -40,4 +40,4 b''
40 }, "haskell")
40 }, "haskell")
41
41
42 CodeMirror.defineMIME("text/x-literate-haskell", "haskell-literate")
42 CodeMirror.defineMIME("text/x-literate-haskell", "haskell-literate")
43 })
43 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -56,7 +56,7 b' CodeMirror.defineMode("haskell", functio'
56 if (source.eat('\'')) {
56 if (source.eat('\'')) {
57 return "string";
57 return "string";
58 }
58 }
59 return "error";
59 return "string error";
60 }
60 }
61
61
62 if (ch == '"') {
62 if (ch == '"') {
@@ -166,7 +166,7 b' CodeMirror.defineMode("haskell", functio'
166 }
166 }
167 }
167 }
168 setState(normal);
168 setState(normal);
169 return "error";
169 return "string error";
170 }
170 }
171
171
172 function stringGap(source, setState) {
172 function stringGap(source, setState) {
@@ -194,16 +194,17 b' CodeMirror.defineMode("haskell", functio'
194 "module", "newtype", "of", "then", "type", "where", "_");
194 "module", "newtype", "of", "then", "type", "where", "_");
195
195
196 setType("keyword")(
196 setType("keyword")(
197 "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
197 "\.\.", ":", "::", "=", "\\", "<-", "->", "@", "~", "=>");
198
198
199 setType("builtin")(
199 setType("builtin")(
200 "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
200 "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<*", "<=",
201 "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
201 "<$>", "<*>", "=<<", "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*",
202 "*>", "**");
202
203
203 setType("builtin")(
204 setType("builtin")(
204 "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq",
205 "Applicative", "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum",
205 "False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT",
206 "Eq", "False", "FilePath", "Float", "Floating", "Fractional", "Functor",
206 "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
207 "GT", "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
207 "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
208 "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
208 "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
209 "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
209 "String", "True");
210 "String", "True");
@@ -223,7 +224,7 b' CodeMirror.defineMode("haskell", functio'
223 "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
224 "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
224 "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
225 "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
225 "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
226 "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
226 "otherwise", "pi", "pred", "print", "product", "properFraction",
227 "otherwise", "pi", "pred", "print", "product", "properFraction", "pure",
227 "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
228 "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
228 "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
229 "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
229 "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
230 "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -485,7 +485,7 b' CodeMirror.defineMode("hxml", function ('
485
485
486 if (state.inString == false && ch == "'") {
486 if (state.inString == false && ch == "'") {
487 state.inString = true;
487 state.inString = true;
488 ch = stream.next();
488 stream.next();
489 }
489 }
490
490
491 if (state.inString == true) {
491 if (state.inString == true) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -14,7 +14,16 b''
14 "use strict";
14 "use strict";
15
15
16 CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
16 CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
17 var closeComment = parserConfig.closeComment || "--%>"
17 return CodeMirror.multiplexingMode(CodeMirror.getMode(config, "htmlmixed"), {
18 return CodeMirror.multiplexingMode(CodeMirror.getMode(config, "htmlmixed"), {
19 open: parserConfig.openComment || "<%--",
20 close: closeComment,
21 delimStyle: "comment",
22 mode: {token: function(stream) {
23 stream.skipTo(closeComment) || stream.skipToEnd()
24 return "comment"
25 }}
26 }, {
18 open: parserConfig.open || parserConfig.scriptStartRegex || "<%",
27 open: parserConfig.open || parserConfig.scriptStartRegex || "<%",
19 close: parserConfig.close || parserConfig.scriptEndRegex || "%>",
28 close: parserConfig.close || parserConfig.scriptEndRegex || "%>",
20 mode: CodeMirror.getMode(config, parserConfig.scriptingModeSpec)
29 mode: CodeMirror.getMode(config, parserConfig.scriptingModeSpec)
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -14,7 +14,7 b''
14 var defaultTags = {
14 var defaultTags = {
15 script: [
15 script: [
16 ["lang", /(javascript|babel)/i, "javascript"],
16 ["lang", /(javascript|babel)/i, "javascript"],
17 ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, "javascript"],
17 ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"],
18 ["type", /./, "text/plain"],
18 ["type", /./, "text/plain"],
19 [null, null, "javascript"]
19 [null, null, "javascript"]
20 ],
20 ],
@@ -44,13 +44,9 b''
44 return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
44 return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
45 }
45 }
46
46
47 function getAttrValue(stream, attr) {
47 function getAttrValue(text, attr) {
48 var pos = stream.pos, match;
48 var match = text.match(getAttrRegexp(attr))
49 while (pos >= 0 && stream.string.charAt(pos) !== "<") pos--;
49 return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
50 if (pos < 0) return pos;
51 if (match = stream.string.slice(pos, stream.pos).match(getAttrRegexp(attr)))
52 return match[2];
53 return "";
54 }
50 }
55
51
56 function getTagRegexp(tagName, anchored) {
52 function getTagRegexp(tagName, anchored) {
@@ -66,10 +62,10 b''
66 }
62 }
67 }
63 }
68
64
69 function findMatchingMode(tagInfo, stream) {
65 function findMatchingMode(tagInfo, tagText) {
70 for (var i = 0; i < tagInfo.length; i++) {
66 for (var i = 0; i < tagInfo.length; i++) {
71 var spec = tagInfo[i];
67 var spec = tagInfo[i];
72 if (!spec[0] || spec[1].test(getAttrValue(stream, spec[0]))) return spec[2];
68 if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
73 }
69 }
74 }
70 }
75
71
@@ -89,15 +85,17 b''
89 tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
85 tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
90
86
91 function html(stream, state) {
87 function html(stream, state) {
92 var tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase();
88 var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
93 var tagInfo = tagName && tags.hasOwnProperty(tagName) && tags[tagName];
89 if (tag && !/[<>\s\/]/.test(stream.current()) &&
94
90 (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
95 var style = htmlMode.token(stream, state.htmlState), modeSpec;
91 tags.hasOwnProperty(tagName)) {
96
92 state.inTag = tagName + " "
97 if (tagInfo && /\btag\b/.test(style) && stream.current() === ">" &&
93 } else if (state.inTag && tag && />$/.test(stream.current())) {
98 (modeSpec = findMatchingMode(tagInfo, stream))) {
94 var inTag = /^([\S]+) (.*)/.exec(state.inTag)
99 var mode = CodeMirror.getMode(config, modeSpec);
95 state.inTag = null
100 var endTagA = getTagRegexp(tagName, true), endTag = getTagRegexp(tagName, false);
96 var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
97 var mode = CodeMirror.getMode(config, modeSpec)
98 var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
101 state.token = function (stream, state) {
99 state.token = function (stream, state) {
102 if (stream.match(endTagA, false)) {
100 if (stream.match(endTagA, false)) {
103 state.token = html;
101 state.token = html;
@@ -107,15 +105,18 b''
107 return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
105 return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
108 };
106 };
109 state.localMode = mode;
107 state.localMode = mode;
110 state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
108 state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "", ""));
109 } else if (state.inTag) {
110 state.inTag += stream.current()
111 if (stream.eol()) state.inTag += " "
111 }
112 }
112 return style;
113 return style;
113 };
114 };
114
115
115 return {
116 return {
116 startState: function () {
117 startState: function () {
117 var state = htmlMode.startState();
118 var state = CodeMirror.startState(htmlMode);
118 return {token: html, localMode: null, localState: null, htmlState: state};
119 return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
119 },
120 },
120
121
121 copyState: function (state) {
122 copyState: function (state) {
@@ -123,7 +124,8 b''
123 if (state.localState) {
124 if (state.localState) {
124 local = CodeMirror.copyState(state.localMode, state.localState);
125 local = CodeMirror.copyState(state.localMode, state.localState);
125 }
126 }
126 return {token: state.token, localMode: state.localMode, localState: local,
127 return {token: state.token, inTag: state.inTag,
128 localMode: state.localMode, localState: local,
127 htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
129 htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
128 },
130 },
129
131
@@ -131,11 +133,11 b''
131 return state.token(stream, state);
133 return state.token(stream, state);
132 },
134 },
133
135
134 indent: function (state, textAfter) {
136 indent: function (state, textAfter, line) {
135 if (!state.localMode || /^\s*<\//.test(textAfter))
137 if (!state.localMode || /^\s*<\//.test(textAfter))
136 return htmlMode.indent(state.htmlState, textAfter);
138 return htmlMode.indent(state.htmlState, textAfter, line);
137 else if (state.localMode.indent)
139 else if (state.localMode.indent)
138 return state.localMode.indent(state.localState, textAfter);
140 return state.localMode.indent(state.localState, textAfter, line);
139 else
141 else
140 return CodeMirror.Pass;
142 return CodeMirror.Pass;
141 },
143 },
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
This diff has been collapsed as it changes many lines, (520 lines changed) Show them Hide them
@@ -1,7 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
4 // TODO actually recognize syntax of TypeScript constructs
5
3
6 (function(mod) {
4 (function(mod) {
7 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -13,11 +11,6 b''
13 })(function(CodeMirror) {
11 })(function(CodeMirror) {
14 "use strict";
12 "use strict";
15
13
16 function expressionAllowed(stream, state, backUp) {
17 return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
18 (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
19 }
20
21 CodeMirror.defineMode("javascript", function(config, parserConfig) {
14 CodeMirror.defineMode("javascript", function(config, parserConfig) {
22 var indentUnit = config.indentUnit;
15 var indentUnit = config.indentUnit;
23 var statementIndent = parserConfig.statementIndent;
16 var statementIndent = parserConfig.statementIndent;
@@ -30,54 +23,24 b' CodeMirror.defineMode("javascript", func'
30
23
31 var keywords = function(){
24 var keywords = function(){
32 function kw(type) {return {type: type, style: "keyword"};}
25 function kw(type) {return {type: type, style: "keyword"};}
33 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
26 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
34 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
27 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
35
28
36 var jsKeywords = {
29 return {
37 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
30 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
38 "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
31 "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
39 "var": kw("var"), "const": kw("var"), "let": kw("var"),
32 "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
40 "function": kw("function"), "catch": kw("catch"),
33 "function": kw("function"), "catch": kw("catch"),
41 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
34 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
42 "in": operator, "typeof": operator, "instanceof": operator,
35 "in": operator, "typeof": operator, "instanceof": operator,
43 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
36 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
44 "this": kw("this"), "class": kw("class"), "super": kw("atom"),
37 "this": kw("this"), "class": kw("class"), "super": kw("atom"),
45 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
38 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
39 "await": C
46 };
40 };
47
48 // Extend the 'normal' keywords with the TypeScript language extensions
49 if (isTS) {
50 var type = {type: "variable", style: "variable-3"};
51 var tsKeywords = {
52 // object-like things
53 "interface": kw("class"),
54 "implements": C,
55 "namespace": C,
56 "module": kw("module"),
57 "enum": kw("module"),
58
59 // scope modifiers
60 "public": kw("modifier"),
61 "private": kw("modifier"),
62 "protected": kw("modifier"),
63 "abstract": kw("modifier"),
64
65 // operators
66 "as": operator,
67
68 // types
69 "string": type, "number": type, "boolean": type, "any": type
70 };
71
72 for (var attr in tsKeywords) {
73 jsKeywords[attr] = tsKeywords[attr];
74 }
75 }
76
77 return jsKeywords;
78 }();
41 }();
79
42
80 var isOperatorChar = /[+\-*&%=<>!?|~^]/;
43 var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
81 var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
44 var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
82
45
83 function readRegexp(stream) {
46 function readRegexp(stream) {
@@ -104,7 +67,7 b' CodeMirror.defineMode("javascript", func'
104 if (ch == '"' || ch == "'") {
67 if (ch == '"' || ch == "'") {
105 state.tokenize = tokenString(ch);
68 state.tokenize = tokenString(ch);
106 return state.tokenize(stream, state);
69 return state.tokenize(stream, state);
107 } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
70 } else if (ch == "." && stream.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/)) {
108 return ret("number", "number");
71 return ret("number", "number");
109 } else if (ch == "." && stream.match("..")) {
72 } else if (ch == "." && stream.match("..")) {
110 return ret("spread", "meta");
73 return ret("spread", "meta");
@@ -112,17 +75,10 b' CodeMirror.defineMode("javascript", func'
112 return ret(ch);
75 return ret(ch);
113 } else if (ch == "=" && stream.eat(">")) {
76 } else if (ch == "=" && stream.eat(">")) {
114 return ret("=>", "operator");
77 return ret("=>", "operator");
115 } else if (ch == "0" && stream.eat(/x/i)) {
78 } else if (ch == "0" && stream.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/)) {
116 stream.eatWhile(/[\da-f]/i);
117 return ret("number", "number");
118 } else if (ch == "0" && stream.eat(/o/i)) {
119 stream.eatWhile(/[0-7]/i);
120 return ret("number", "number");
121 } else if (ch == "0" && stream.eat(/b/i)) {
122 stream.eatWhile(/[01]/i);
123 return ret("number", "number");
79 return ret("number", "number");
124 } else if (/\d/.test(ch)) {
80 } else if (/\d/.test(ch)) {
125 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
81 stream.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/);
126 return ret("number", "number");
82 return ret("number", "number");
127 } else if (ch == "/") {
83 } else if (ch == "/") {
128 if (stream.eat("*")) {
84 if (stream.eat("*")) {
@@ -133,10 +89,10 b' CodeMirror.defineMode("javascript", func'
133 return ret("comment", "comment");
89 return ret("comment", "comment");
134 } else if (expressionAllowed(stream, state, 1)) {
90 } else if (expressionAllowed(stream, state, 1)) {
135 readRegexp(stream);
91 readRegexp(stream);
136 stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
92 stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/);
137 return ret("regexp", "string-2");
93 return ret("regexp", "string-2");
138 } else {
94 } else {
139 stream.eatWhile(isOperatorChar);
95 stream.eat("=");
140 return ret("operator", "operator", stream.current());
96 return ret("operator", "operator", stream.current());
141 }
97 }
142 } else if (ch == "`") {
98 } else if (ch == "`") {
@@ -145,14 +101,31 b' CodeMirror.defineMode("javascript", func'
145 } else if (ch == "#") {
101 } else if (ch == "#") {
146 stream.skipToEnd();
102 stream.skipToEnd();
147 return ret("error", "error");
103 return ret("error", "error");
104 } else if (ch == "<" && stream.match("!--") || ch == "-" && stream.match("->")) {
105 stream.skipToEnd()
106 return ret("comment", "comment")
148 } else if (isOperatorChar.test(ch)) {
107 } else if (isOperatorChar.test(ch)) {
149 stream.eatWhile(isOperatorChar);
108 if (ch != ">" || !state.lexical || state.lexical.type != ">") {
109 if (stream.eat("=")) {
110 if (ch == "!" || ch == "=") stream.eat("=")
111 } else if (/[<>*+\-]/.test(ch)) {
112 stream.eat(ch)
113 if (ch == ">") stream.eat(ch)
114 }
115 }
150 return ret("operator", "operator", stream.current());
116 return ret("operator", "operator", stream.current());
151 } else if (wordRE.test(ch)) {
117 } else if (wordRE.test(ch)) {
152 stream.eatWhile(wordRE);
118 stream.eatWhile(wordRE);
153 var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
119 var word = stream.current()
154 return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
120 if (state.lastType != ".") {
155 ret("variable", "variable", word);
121 if (keywords.propertyIsEnumerable(word)) {
122 var kw = keywords[word]
123 return ret(kw.type, kw.style, word)
124 }
125 if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false))
126 return ret("async", "keyword", word)
127 }
128 return ret("variable", "variable", word)
156 }
129 }
157 }
130 }
158
131
@@ -209,19 +182,28 b' CodeMirror.defineMode("javascript", func'
209 var arrow = stream.string.indexOf("=>", stream.start);
182 var arrow = stream.string.indexOf("=>", stream.start);
210 if (arrow < 0) return;
183 if (arrow < 0) return;
211
184
185 if (isTS) { // Try to skip TypeScript return type declarations after the arguments
186 var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
187 if (m) arrow = m.index
188 }
189
212 var depth = 0, sawSomething = false;
190 var depth = 0, sawSomething = false;
213 for (var pos = arrow - 1; pos >= 0; --pos) {
191 for (var pos = arrow - 1; pos >= 0; --pos) {
214 var ch = stream.string.charAt(pos);
192 var ch = stream.string.charAt(pos);
215 var bracket = brackets.indexOf(ch);
193 var bracket = brackets.indexOf(ch);
216 if (bracket >= 0 && bracket < 3) {
194 if (bracket >= 0 && bracket < 3) {
217 if (!depth) { ++pos; break; }
195 if (!depth) { ++pos; break; }
218 if (--depth == 0) break;
196 if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
219 } else if (bracket >= 3 && bracket < 6) {
197 } else if (bracket >= 3 && bracket < 6) {
220 ++depth;
198 ++depth;
221 } else if (wordRE.test(ch)) {
199 } else if (wordRE.test(ch)) {
222 sawSomething = true;
200 sawSomething = true;
223 } else if (/["'\/]/.test(ch)) {
201 } else if (/["'\/`]/.test(ch)) {
224 return;
202 for (;; --pos) {
203 if (pos == 0) return
204 var next = stream.string.charAt(pos - 1)
205 if (next == ch && stream.string.charAt(pos - 2) != "\\") { pos--; break }
206 }
225 } else if (sawSomething && !depth) {
207 } else if (sawSomething && !depth) {
226 ++pos;
208 ++pos;
227 break;
209 break;
@@ -283,35 +265,68 b' CodeMirror.defineMode("javascript", func'
283 pass.apply(null, arguments);
265 pass.apply(null, arguments);
284 return true;
266 return true;
285 }
267 }
286 function register(varname) {
268 function inList(name, list) {
287 function inList(list) {
269 for (var v = list; v; v = v.next) if (v.name == name) return true
288 for (var v = list; v; v = v.next)
289 if (v.name == varname) return true;
290 return false;
270 return false;
291 }
271 }
272 function register(varname) {
292 var state = cx.state;
273 var state = cx.state;
293 cx.marked = "def";
274 cx.marked = "def";
294 if (state.context) {
275 if (state.context) {
295 if (inList(state.localVars)) return;
276 if (state.lexical.info == "var" && state.context && state.context.block) {
296 state.localVars = {name: varname, next: state.localVars};
277 // FIXME function decls are also not block scoped
278 var newContext = registerVarScoped(varname, state.context)
279 if (newContext != null) {
280 state.context = newContext
281 return
282 }
283 } else if (!inList(varname, state.localVars)) {
284 state.localVars = new Var(varname, state.localVars)
285 return
286 }
287 }
288 // Fall through means this is global
289 if (parserConfig.globalVars && !inList(varname, state.globalVars))
290 state.globalVars = new Var(varname, state.globalVars)
291 }
292 function registerVarScoped(varname, context) {
293 if (!context) {
294 return null
295 } else if (context.block) {
296 var inner = registerVarScoped(varname, context.prev)
297 if (!inner) return null
298 if (inner == context.prev) return context
299 return new Context(inner, context.vars, true)
300 } else if (inList(varname, context.vars)) {
301 return context
297 } else {
302 } else {
298 if (inList(state.globalVars)) return;
303 return new Context(context.prev, new Var(varname, context.vars), false)
299 if (parserConfig.globalVars)
304 }
300 state.globalVars = {name: varname, next: state.globalVars};
301 }
305 }
306
307 function isModifier(name) {
308 return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"
302 }
309 }
303
310
304 // Combinators
311 // Combinators
305
312
306 var defaultVars = {name: "this", next: {name: "arguments"}};
313 function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block }
314 function Var(name, next) { this.name = name; this.next = next }
315
316 var defaultVars = new Var("this", new Var("arguments", null))
307 function pushcontext() {
317 function pushcontext() {
308 cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
318 cx.state.context = new Context(cx.state.context, cx.state.localVars, false)
309 cx.state.localVars = defaultVars;
319 cx.state.localVars = defaultVars
320 }
321 function pushblockcontext() {
322 cx.state.context = new Context(cx.state.context, cx.state.localVars, true)
323 cx.state.localVars = null
310 }
324 }
311 function popcontext() {
325 function popcontext() {
312 cx.state.localVars = cx.state.context.vars;
326 cx.state.localVars = cx.state.context.vars
313 cx.state.context = cx.state.context.prev;
327 cx.state.context = cx.state.context.prev
314 }
328 }
329 popcontext.lex = true
315 function pushlex(type, info) {
330 function pushlex(type, info) {
316 var result = function() {
331 var result = function() {
317 var state = cx.state, indent = state.indented;
332 var state = cx.state, indent = state.indented;
@@ -336,71 +351,99 b' CodeMirror.defineMode("javascript", func'
336 function expect(wanted) {
351 function expect(wanted) {
337 function exp(type) {
352 function exp(type) {
338 if (type == wanted) return cont();
353 if (type == wanted) return cont();
339 else if (wanted == ";") return pass();
354 else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass();
340 else return cont(exp);
355 else return cont(exp);
341 };
356 };
342 return exp;
357 return exp;
343 }
358 }
344
359
345 function statement(type, value) {
360 function statement(type, value) {
346 if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
361 if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex);
347 if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
362 if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
348 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
363 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
349 if (type == "{") return cont(pushlex("}"), block, poplex);
364 if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);
365 if (type == "debugger") return cont(expect(";"));
366 if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext);
350 if (type == ";") return cont();
367 if (type == ";") return cont();
351 if (type == "if") {
368 if (type == "if") {
352 if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
369 if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
353 cx.state.cc.pop()();
370 cx.state.cc.pop()();
354 return cont(pushlex("form"), expression, statement, poplex, maybeelse);
371 return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
355 }
372 }
356 if (type == "function") return cont(functiondef);
373 if (type == "function") return cont(functiondef);
357 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
374 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
358 if (type == "variable") return cont(pushlex("stat"), maybelabel);
375 if (type == "class" || (isTS && value == "interface")) {
359 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
376 cx.marked = "keyword"
360 block, poplex, poplex);
377 return cont(pushlex("form", type == "class" ? type : value), className, poplex)
378 }
379 if (type == "variable") {
380 if (isTS && value == "declare") {
381 cx.marked = "keyword"
382 return cont(statement)
383 } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
384 cx.marked = "keyword"
385 if (value == "enum") return cont(enumdef);
386 else if (value == "type") return cont(typename, expect("operator"), typeexpr, expect(";"));
387 else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
388 } else if (isTS && value == "namespace") {
389 cx.marked = "keyword"
390 return cont(pushlex("form"), expression, statement, poplex)
391 } else if (isTS && value == "abstract") {
392 cx.marked = "keyword"
393 return cont(statement)
394 } else {
395 return cont(pushlex("stat"), maybelabel);
396 }
397 }
398 if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext,
399 block, poplex, poplex, popcontext);
361 if (type == "case") return cont(expression, expect(":"));
400 if (type == "case") return cont(expression, expect(":"));
362 if (type == "default") return cont(expect(":"));
401 if (type == "default") return cont(expect(":"));
363 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
402 if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext);
364 statement, poplex, popcontext);
365 if (type == "class") return cont(pushlex("form"), className, poplex);
366 if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
403 if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
367 if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
404 if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
368 if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex)
405 if (type == "async") return cont(statement)
406 if (value == "@") return cont(expression, statement)
369 return pass(pushlex("stat"), expression, expect(";"), poplex);
407 return pass(pushlex("stat"), expression, expect(";"), poplex);
370 }
408 }
371 function expression(type) {
409 function maybeCatchBinding(type) {
372 return expressionInner(type, false);
410 if (type == "(") return cont(funarg, expect(")"))
411 }
412 function expression(type, value) {
413 return expressionInner(type, value, false);
373 }
414 }
374 function expressionNoComma(type) {
415 function expressionNoComma(type, value) {
375 return expressionInner(type, true);
416 return expressionInner(type, value, true);
376 }
417 }
377 function expressionInner(type, noComma) {
418 function parenExpr(type) {
419 if (type != "(") return pass()
420 return cont(pushlex(")"), expression, expect(")"), poplex)
421 }
422 function expressionInner(type, value, noComma) {
378 if (cx.state.fatArrowAt == cx.stream.start) {
423 if (cx.state.fatArrowAt == cx.stream.start) {
379 var body = noComma ? arrowBodyNoComma : arrowBody;
424 var body = noComma ? arrowBodyNoComma : arrowBody;
380 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
425 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
381 else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
426 else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
382 }
427 }
383
428
384 var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
429 var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
385 if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
430 if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
386 if (type == "function") return cont(functiondef, maybeop);
431 if (type == "function") return cont(functiondef, maybeop);
387 if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
432 if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
388 if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
433 if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
434 if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
389 if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
435 if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
390 if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
436 if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
391 if (type == "{") return contCommasep(objprop, "}", null, maybeop);
437 if (type == "{") return contCommasep(objprop, "}", null, maybeop);
392 if (type == "quasi") return pass(quasi, maybeop);
438 if (type == "quasi") return pass(quasi, maybeop);
393 if (type == "new") return cont(maybeTarget(noComma));
439 if (type == "new") return cont(maybeTarget(noComma));
440 if (type == "import") return cont(expression);
394 return cont();
441 return cont();
395 }
442 }
396 function maybeexpression(type) {
443 function maybeexpression(type) {
397 if (type.match(/[;\}\)\],]/)) return pass();
444 if (type.match(/[;\}\)\],]/)) return pass();
398 return pass(expression);
445 return pass(expression);
399 }
446 }
400 function maybeexpressionNoComma(type) {
401 if (type.match(/[;\}\)\],]/)) return pass();
402 return pass(expressionNoComma);
403 }
404
447
405 function maybeoperatorComma(type, value) {
448 function maybeoperatorComma(type, value) {
406 if (type == ",") return cont(expression);
449 if (type == ",") return cont(expression);
@@ -411,7 +454,9 b' CodeMirror.defineMode("javascript", func'
411 var expr = noComma == false ? expression : expressionNoComma;
454 var expr = noComma == false ? expression : expressionNoComma;
412 if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
455 if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
413 if (type == "operator") {
456 if (type == "operator") {
414 if (/\+\+|--/.test(value)) return cont(me);
457 if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
458 if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false))
459 return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
415 if (value == "?") return cont(expression, expect(":"), expr);
460 if (value == "?") return cont(expression, expect(":"), expr);
416 return cont(expr);
461 return cont(expr);
417 }
462 }
@@ -420,6 +465,12 b' CodeMirror.defineMode("javascript", func'
420 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
465 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
421 if (type == ".") return cont(property, me);
466 if (type == ".") return cont(property, me);
422 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
467 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
468 if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
469 if (type == "regexp") {
470 cx.state.lastType = cx.marked = "operator"
471 cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
472 return cont(expr)
473 }
423 }
474 }
424 function quasi(type, value) {
475 function quasi(type, value) {
425 if (type != "quasi") return pass();
476 if (type != "quasi") return pass();
@@ -444,6 +495,7 b' CodeMirror.defineMode("javascript", func'
444 function maybeTarget(noComma) {
495 function maybeTarget(noComma) {
445 return function(type) {
496 return function(type) {
446 if (type == ".") return cont(noComma ? targetNoComma : target);
497 if (type == ".") return cont(noComma ? targetNoComma : target);
498 else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
447 else return pass(noComma ? expressionNoComma : expression);
499 else return pass(noComma ? expressionNoComma : expression);
448 };
500 };
449 }
501 }
@@ -461,21 +513,33 b' CodeMirror.defineMode("javascript", func'
461 if (type == "variable") {cx.marked = "property"; return cont();}
513 if (type == "variable") {cx.marked = "property"; return cont();}
462 }
514 }
463 function objprop(type, value) {
515 function objprop(type, value) {
464 if (type == "variable" || cx.style == "keyword") {
516 if (type == "async") {
517 cx.marked = "property";
518 return cont(objprop);
519 } else if (type == "variable" || cx.style == "keyword") {
465 cx.marked = "property";
520 cx.marked = "property";
466 if (value == "get" || value == "set") return cont(getterSetter);
521 if (value == "get" || value == "set") return cont(getterSetter);
522 var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
523 if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
524 cx.state.fatArrowAt = cx.stream.pos + m[0].length
467 return cont(afterprop);
525 return cont(afterprop);
468 } else if (type == "number" || type == "string") {
526 } else if (type == "number" || type == "string") {
469 cx.marked = jsonldMode ? "property" : (cx.style + " property");
527 cx.marked = jsonldMode ? "property" : (cx.style + " property");
470 return cont(afterprop);
528 return cont(afterprop);
471 } else if (type == "jsonld-keyword") {
529 } else if (type == "jsonld-keyword") {
472 return cont(afterprop);
530 return cont(afterprop);
473 } else if (type == "modifier") {
531 } else if (isTS && isModifier(value)) {
532 cx.marked = "keyword"
474 return cont(objprop)
533 return cont(objprop)
475 } else if (type == "[") {
534 } else if (type == "[") {
476 return cont(expression, expect("]"), afterprop);
535 return cont(expression, maybetype, expect("]"), afterprop);
477 } else if (type == "spread") {
536 } else if (type == "spread") {
478 return cont(expression);
537 return cont(expressionNoComma, afterprop);
538 } else if (value == "*") {
539 cx.marked = "keyword";
540 return cont(objprop);
541 } else if (type == ":") {
542 return pass(afterprop)
479 }
543 }
480 }
544 }
481 function getterSetter(type) {
545 function getterSetter(type) {
@@ -487,18 +551,22 b' CodeMirror.defineMode("javascript", func'
487 if (type == ":") return cont(expressionNoComma);
551 if (type == ":") return cont(expressionNoComma);
488 if (type == "(") return pass(functiondef);
552 if (type == "(") return pass(functiondef);
489 }
553 }
490 function commasep(what, end) {
554 function commasep(what, end, sep) {
491 function proceed(type) {
555 function proceed(type, value) {
492 if (type == ",") {
556 if (sep ? sep.indexOf(type) > -1 : type == ",") {
493 var lex = cx.state.lexical;
557 var lex = cx.state.lexical;
494 if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
558 if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
495 return cont(what, proceed);
559 return cont(function(type, value) {
560 if (type == end || value == end) return pass()
561 return pass(what)
562 }, proceed);
496 }
563 }
497 if (type == end) return cont();
564 if (type == end || value == end) return cont();
565 if (sep && sep.indexOf(";") > -1) return pass(what)
498 return cont(expect(end));
566 return cont(expect(end));
499 }
567 }
500 return function(type) {
568 return function(type, value) {
501 if (type == end) return cont();
569 if (type == end || value == end) return cont();
502 return pass(what, proceed);
570 return pass(what, proceed);
503 };
571 };
504 }
572 }
@@ -511,23 +579,91 b' CodeMirror.defineMode("javascript", func'
511 if (type == "}") return cont();
579 if (type == "}") return cont();
512 return pass(statement, block);
580 return pass(statement, block);
513 }
581 }
514 function maybetype(type) {
582 function maybetype(type, value) {
515 if (isTS && type == ":") return cont(typedef);
583 if (isTS) {
584 if (type == ":") return cont(typeexpr);
585 if (value == "?") return cont(maybetype);
586 }
587 }
588 function maybetypeOrIn(type, value) {
589 if (isTS && (type == ":" || value == "in")) return cont(typeexpr)
590 }
591 function mayberettype(type) {
592 if (isTS && type == ":") {
593 if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
594 else return cont(typeexpr)
595 }
596 }
597 function isKW(_, value) {
598 if (value == "is") {
599 cx.marked = "keyword"
600 return cont()
601 }
602 }
603 function typeexpr(type, value) {
604 if (value == "keyof" || value == "typeof" || value == "infer") {
605 cx.marked = "keyword"
606 return cont(value == "typeof" ? expressionNoComma : typeexpr)
607 }
608 if (type == "variable" || value == "void") {
609 cx.marked = "type"
610 return cont(afterType)
611 }
612 if (value == "|" || value == "&") return cont(typeexpr)
613 if (type == "string" || type == "number" || type == "atom") return cont(afterType);
614 if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
615 if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
616 if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType, afterType)
617 if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)
516 }
618 }
517 function maybedefault(_, value) {
619 function maybeReturnType(type) {
518 if (value == "=") return cont(expressionNoComma);
620 if (type == "=>") return cont(typeexpr)
621 }
622 function typeprop(type, value) {
623 if (type == "variable" || cx.style == "keyword") {
624 cx.marked = "property"
625 return cont(typeprop)
626 } else if (value == "?" || type == "number" || type == "string") {
627 return cont(typeprop)
628 } else if (type == ":") {
629 return cont(typeexpr)
630 } else if (type == "[") {
631 return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop)
632 } else if (type == "(") {
633 return pass(functiondecl, typeprop)
634 }
519 }
635 }
520 function typedef(type) {
636 function typearg(type, value) {
521 if (type == "variable") {cx.marked = "variable-3"; return cont();}
637 if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)
638 if (type == ":") return cont(typeexpr)
639 if (type == "spread") return cont(typearg)
640 return pass(typeexpr)
522 }
641 }
523 function vardef() {
642 function afterType(type, value) {
643 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
644 if (value == "|" || type == "." || value == "&") return cont(typeexpr)
645 if (type == "[") return cont(typeexpr, expect("]"), afterType)
646 if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
647 if (value == "?") return cont(typeexpr, expect(":"), typeexpr)
648 }
649 function maybeTypeArgs(_, value) {
650 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
651 }
652 function typeparam() {
653 return pass(typeexpr, maybeTypeDefault)
654 }
655 function maybeTypeDefault(_, value) {
656 if (value == "=") return cont(typeexpr)
657 }
658 function vardef(_, value) {
659 if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)}
524 return pass(pattern, maybetype, maybeAssign, vardefCont);
660 return pass(pattern, maybetype, maybeAssign, vardefCont);
525 }
661 }
526 function pattern(type, value) {
662 function pattern(type, value) {
527 if (type == "modifier") return cont(pattern)
663 if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
528 if (type == "variable") { register(value); return cont(); }
664 if (type == "variable") { register(value); return cont(); }
529 if (type == "spread") return cont(pattern);
665 if (type == "spread") return cont(pattern);
530 if (type == "[") return contCommasep(pattern, "]");
666 if (type == "[") return contCommasep(eltpattern, "]");
531 if (type == "{") return contCommasep(proppattern, "}");
667 if (type == "{") return contCommasep(proppattern, "}");
532 }
668 }
533 function proppattern(type, value) {
669 function proppattern(type, value) {
@@ -538,8 +674,12 b' CodeMirror.defineMode("javascript", func'
538 if (type == "variable") cx.marked = "property";
674 if (type == "variable") cx.marked = "property";
539 if (type == "spread") return cont(pattern);
675 if (type == "spread") return cont(pattern);
540 if (type == "}") return pass();
676 if (type == "}") return pass();
677 if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern);
541 return cont(expect(":"), pattern, maybeAssign);
678 return cont(expect(":"), pattern, maybeAssign);
542 }
679 }
680 function eltpattern() {
681 return pass(pattern, maybeAssign)
682 }
543 function maybeAssign(_type, value) {
683 function maybeAssign(_type, value) {
544 if (value == "=") return cont(expressionNoComma);
684 if (value == "=") return cont(expressionNoComma);
545 }
685 }
@@ -549,73 +689,109 b' CodeMirror.defineMode("javascript", func'
549 function maybeelse(type, value) {
689 function maybeelse(type, value) {
550 if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
690 if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
551 }
691 }
552 function forspec(type) {
692 function forspec(type, value) {
553 if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
693 if (value == "await") return cont(forspec);
694 if (type == "(") return cont(pushlex(")"), forspec1, poplex);
554 }
695 }
555 function forspec1(type) {
696 function forspec1(type) {
556 if (type == "var") return cont(vardef, expect(";"), forspec2);
697 if (type == "var") return cont(vardef, forspec2);
557 if (type == ";") return cont(forspec2);
698 if (type == "variable") return cont(forspec2);
558 if (type == "variable") return cont(formaybeinof);
699 return pass(forspec2)
559 return pass(expression, expect(";"), forspec2);
560 }
561 function formaybeinof(_type, value) {
562 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
563 return cont(maybeoperatorComma, forspec2);
564 }
700 }
565 function forspec2(type, value) {
701 function forspec2(type, value) {
566 if (type == ";") return cont(forspec3);
702 if (type == ")") return cont()
567 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
703 if (type == ";") return cont(forspec2)
568 return pass(expression, expect(";"), forspec3);
704 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression, forspec2) }
569 }
705 return pass(expression, forspec2)
570 function forspec3(type) {
571 if (type != ")") cont(expression);
572 }
706 }
573 function functiondef(type, value) {
707 function functiondef(type, value) {
574 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
708 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
575 if (type == "variable") {register(value); return cont(functiondef);}
709 if (type == "variable") {register(value); return cont(functiondef);}
576 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
710 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);
711 if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)
712 }
713 function functiondecl(type, value) {
714 if (value == "*") {cx.marked = "keyword"; return cont(functiondecl);}
715 if (type == "variable") {register(value); return cont(functiondecl);}
716 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, popcontext);
717 if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondecl)
577 }
718 }
578 function funarg(type) {
719 function typename(type, value) {
720 if (type == "keyword" || type == "variable") {
721 cx.marked = "type"
722 return cont(typename)
723 } else if (value == "<") {
724 return cont(pushlex(">"), commasep(typeparam, ">"), poplex)
725 }
726 }
727 function funarg(type, value) {
728 if (value == "@") cont(expression, funarg)
579 if (type == "spread") return cont(funarg);
729 if (type == "spread") return cont(funarg);
580 return pass(pattern, maybetype, maybedefault);
730 if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
731 if (isTS && type == "this") return cont(maybetype, maybeAssign)
732 return pass(pattern, maybetype, maybeAssign);
733 }
734 function classExpression(type, value) {
735 // Class expressions may have an optional name.
736 if (type == "variable") return className(type, value);
737 return classNameAfter(type, value);
581 }
738 }
582 function className(type, value) {
739 function className(type, value) {
583 if (type == "variable") {register(value); return cont(classNameAfter);}
740 if (type == "variable") {register(value); return cont(classNameAfter);}
584 }
741 }
585 function classNameAfter(type, value) {
742 function classNameAfter(type, value) {
586 if (value == "extends") return cont(expression, classNameAfter);
743 if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
744 if (value == "extends" || value == "implements" || (isTS && type == ",")) {
745 if (value == "implements") cx.marked = "keyword";
746 return cont(isTS ? typeexpr : expression, classNameAfter);
747 }
587 if (type == "{") return cont(pushlex("}"), classBody, poplex);
748 if (type == "{") return cont(pushlex("}"), classBody, poplex);
588 }
749 }
589 function classBody(type, value) {
750 function classBody(type, value) {
590 if (type == "variable" || cx.style == "keyword") {
751 if (type == "async" ||
591 if (value == "static") {
752 (type == "variable" &&
753 (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&
754 cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
592 cx.marked = "keyword";
755 cx.marked = "keyword";
593 return cont(classBody);
756 return cont(classBody);
594 }
757 }
758 if (type == "variable" || cx.style == "keyword") {
595 cx.marked = "property";
759 cx.marked = "property";
596 if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
760 return cont(isTS ? classfield : functiondef, classBody);
597 return cont(functiondef, classBody);
598 }
761 }
762 if (type == "number" || type == "string") return cont(isTS ? classfield : functiondef, classBody);
763 if (type == "[")
764 return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
599 if (value == "*") {
765 if (value == "*") {
600 cx.marked = "keyword";
766 cx.marked = "keyword";
601 return cont(classBody);
767 return cont(classBody);
602 }
768 }
603 if (type == ";") return cont(classBody);
769 if (isTS && type == "(") return pass(functiondecl, classBody)
770 if (type == ";" || type == ",") return cont(classBody);
604 if (type == "}") return cont();
771 if (type == "}") return cont();
772 if (value == "@") return cont(expression, classBody)
605 }
773 }
606 function classGetterSetter(type) {
774 function classfield(type, value) {
607 if (type != "variable") return pass();
775 if (value == "?") return cont(classfield)
608 cx.marked = "property";
776 if (type == ":") return cont(typeexpr, maybeAssign)
609 return cont();
777 if (value == "=") return cont(expressionNoComma)
778 var context = cx.state.lexical.prev, isInterface = context && context.info == "interface"
779 return pass(isInterface ? functiondecl : functiondef)
610 }
780 }
611 function afterExport(_type, value) {
781 function afterExport(type, value) {
612 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
782 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
613 if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
783 if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
784 if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
614 return pass(statement);
785 return pass(statement);
615 }
786 }
787 function exportField(type, value) {
788 if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
789 if (type == "variable") return pass(expressionNoComma, exportField);
790 }
616 function afterImport(type) {
791 function afterImport(type) {
617 if (type == "string") return cont();
792 if (type == "string") return cont();
618 return pass(importSpec, maybeFrom);
793 if (type == "(") return pass(expression);
794 return pass(importSpec, maybeMoreImports, maybeFrom);
619 }
795 }
620 function importSpec(type, value) {
796 function importSpec(type, value) {
621 if (type == "{") return contCommasep(importSpec, "}");
797 if (type == "{") return contCommasep(importSpec, "}");
@@ -623,6 +799,9 b' CodeMirror.defineMode("javascript", func'
623 if (value == "*") cx.marked = "keyword";
799 if (value == "*") cx.marked = "keyword";
624 return cont(maybeAs);
800 return cont(maybeAs);
625 }
801 }
802 function maybeMoreImports(type) {
803 if (type == ",") return cont(importSpec, maybeMoreImports)
804 }
626 function maybeAs(_type, value) {
805 function maybeAs(_type, value) {
627 if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
806 if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
628 }
807 }
@@ -631,16 +810,13 b' CodeMirror.defineMode("javascript", func'
631 }
810 }
632 function arrayLiteral(type) {
811 function arrayLiteral(type) {
633 if (type == "]") return cont();
812 if (type == "]") return cont();
634 return pass(expressionNoComma, maybeArrayComprehension);
635 }
636 function maybeArrayComprehension(type) {
637 if (type == "for") return pass(comprehension, expect("]"));
638 if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
639 return pass(commasep(expressionNoComma, "]"));
813 return pass(commasep(expressionNoComma, "]"));
640 }
814 }
641 function comprehension(type) {
815 function enumdef() {
642 if (type == "for") return cont(forspec, comprehension);
816 return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex)
643 if (type == "if") return cont(expression, comprehension);
817 }
818 function enummember() {
819 return pass(pattern, maybeAssign);
644 }
820 }
645
821
646 function isContinuedStatement(state, textAfter) {
822 function isContinuedStatement(state, textAfter) {
@@ -649,6 +825,12 b' CodeMirror.defineMode("javascript", func'
649 /[,.]/.test(textAfter.charAt(0));
825 /[,.]/.test(textAfter.charAt(0));
650 }
826 }
651
827
828 function expressionAllowed(stream, state, backUp) {
829 return state.tokenize == tokenBase &&
830 /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
831 (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
832 }
833
652 // Interface
834 // Interface
653
835
654 return {
836 return {
@@ -659,7 +841,7 b' CodeMirror.defineMode("javascript", func'
659 cc: [],
841 cc: [],
660 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
842 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
661 localVars: parserConfig.localVars,
843 localVars: parserConfig.localVars,
662 context: parserConfig.localVars && {vars: parserConfig.localVars},
844 context: parserConfig.localVars && new Context(null, null, false),
663 indented: basecolumn || 0
845 indented: basecolumn || 0
664 };
846 };
665 if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
847 if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
@@ -684,19 +866,23 b' CodeMirror.defineMode("javascript", func'
684 indent: function(state, textAfter) {
866 indent: function(state, textAfter) {
685 if (state.tokenize == tokenComment) return CodeMirror.Pass;
867 if (state.tokenize == tokenComment) return CodeMirror.Pass;
686 if (state.tokenize != tokenBase) return 0;
868 if (state.tokenize != tokenBase) return 0;
687 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
869 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
688 // Kludge to prevent 'maybelse' from blocking lexical scope pops
870 // Kludge to prevent 'maybelse' from blocking lexical scope pops
689 if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
871 if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
690 var c = state.cc[i];
872 var c = state.cc[i];
691 if (c == poplex) lexical = lexical.prev;
873 if (c == poplex) lexical = lexical.prev;
692 else if (c != maybeelse) break;
874 else if (c != maybeelse) break;
693 }
875 }
694 if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
876 while ((lexical.type == "stat" || lexical.type == "form") &&
877 (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
878 (top == maybeoperatorComma || top == maybeoperatorNoComma) &&
879 !/^[,\.=+\-*:?[\(]/.test(textAfter))))
880 lexical = lexical.prev;
695 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
881 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
696 lexical = lexical.prev;
882 lexical = lexical.prev;
697 var type = lexical.type, closing = firstChar == type;
883 var type = lexical.type, closing = firstChar == type;
698
884
699 if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
885 if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0);
700 else if (type == "form" && firstChar == "{") return lexical.indented;
886 else if (type == "form" && firstChar == "{") return lexical.indented;
701 else if (type == "form") return lexical.indented + indentUnit;
887 else if (type == "form") return lexical.indented + indentUnit;
702 else if (type == "stat")
888 else if (type == "stat")
@@ -710,6 +896,7 b' CodeMirror.defineMode("javascript", func'
710 electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
896 electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
711 blockCommentStart: jsonMode ? null : "/*",
897 blockCommentStart: jsonMode ? null : "/*",
712 blockCommentEnd: jsonMode ? null : "*/",
898 blockCommentEnd: jsonMode ? null : "*/",
899 blockCommentContinue: jsonMode ? null : " * ",
713 lineComment: jsonMode ? null : "//",
900 lineComment: jsonMode ? null : "//",
714 fold: "brace",
901 fold: "brace",
715 closeBrackets: "()[]{}''\"\"``",
902 closeBrackets: "()[]{}''\"\"``",
@@ -719,6 +906,7 b' CodeMirror.defineMode("javascript", func'
719 jsonMode: jsonMode,
906 jsonMode: jsonMode,
720
907
721 expressionAllowed: expressionAllowed,
908 expressionAllowed: expressionAllowed,
909
722 skipExpression: function(state) {
910 skipExpression: function(state) {
723 var top = state.cc[state.cc.length - 1]
911 var top = state.cc[state.cc.length - 1]
724 if (top == expression || top == expressionNoComma) state.cc.pop()
912 if (top == expression || top == expressionNoComma) state.cc.pop()
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -107,7 +107,7 b''
107 }
107 }
108 return "variable";
108 return "variable";
109 } else if (stream.eat("{")) {
109 } else if (stream.eat("{")) {
110 if (ch = stream.eat("#")) {
110 if (stream.eat("#")) {
111 state.incomment = true;
111 state.incomment = true;
112 if(!stream.skipTo("#}")) {
112 if(!stream.skipTo("#}")) {
113 stream.skipToEnd();
113 stream.skipToEnd();
@@ -136,7 +136,11 b''
136 },
136 },
137 token: function (stream, state) {
137 token: function (stream, state) {
138 return state.tokenize(stream, state);
138 return state.tokenize(stream, state);
139 }
139 },
140 blockCommentStart: "{#",
141 blockCommentEnd: "#}"
140 };
142 };
141 });
143 });
144
145 CodeMirror.defineMIME("text/jinja2", "jinja2");
142 });
146 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -25,14 +25,14 b''
25 context.prev && copyContext(context.prev))
25 context.prev && copyContext(context.prev))
26 }
26 }
27
27
28 CodeMirror.defineMode("jsx", function(config) {
28 CodeMirror.defineMode("jsx", function(config, modeConfig) {
29 var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false})
29 var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false, allowMissingTagName: true})
30 var jsMode = CodeMirror.getMode(config, "javascript")
30 var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript")
31
31
32 function flatXMLIndent(state) {
32 function flatXMLIndent(state) {
33 var tagName = state.tagName
33 var tagName = state.tagName
34 state.tagName = null
34 state.tagName = null
35 var result = xmlMode.indent(state, "")
35 var result = xmlMode.indent(state, "", "")
36 state.tagName = tagName
36 state.tagName = tagName
37 return result
37 return result
38 }
38 }
@@ -105,7 +105,7 b''
105 function jsToken(stream, state, cx) {
105 function jsToken(stream, state, cx) {
106 if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) {
106 if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) {
107 jsMode.skipExpression(cx.state)
107 jsMode.skipExpression(cx.state)
108 state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "")),
108 state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "", "")),
109 xmlMode, 0, state.context)
109 xmlMode, 0, state.context)
110 return null
110 return null
111 }
111 }
@@ -144,4 +144,5 b''
144 }, "xml", "javascript")
144 }, "xml", "javascript")
145
145
146 CodeMirror.defineMIME("text/jsx", "jsx")
146 CodeMirror.defineMIME("text/jsx", "jsx")
147 })
147 CodeMirror.defineMIME("text/typescript-jsx", {name: "jsx", base: {name: "javascript", typescript: true}})
148 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -11,61 +11,78 b''
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 CodeMirror.defineMode("julia", function(_conf, parserConf) {
14 CodeMirror.defineMode("julia", function(config, parserConf) {
15 var ERRORCLASS = 'error';
15 function wordRegexp(words, end) {
16
16 if (typeof end === "undefined") { end = "\\b"; }
17 function wordRegexp(words) {
17 return new RegExp("^((" + words.join(")|(") + "))" + end);
18 return new RegExp("^((" + words.join(")|(") + "))\\b");
19 }
18 }
20
19
21 var operators = parserConf.operators || /^\.?[|&^\\%*+\-<>!=\/]=?|\?|~|:|\$|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|\bin\b(?!\()|[\u2208\u2209](?!\()/;
20 var octChar = "\\\\[0-7]{1,3}";
21 var hexChar = "\\\\x[A-Fa-f0-9]{1,2}";
22 var sChar = "\\\\[abefnrtv0%?'\"\\\\]";
23 var uChar = "([^\\u0027\\u005C\\uD800-\\uDFFF]|[\\uD800-\\uDFFF][\\uDC00-\\uDFFF])";
24
25 var operators = parserConf.operators || wordRegexp([
26 "[<>]:", "[<>=]=", "<<=?", ">>>?=?", "=>", "->", "\\/\\/",
27 "[\\\\%*+\\-<>!=\\/^|&\\u00F7\\u22BB]=?", "\\?", "\\$", "~", ":",
28 "\\u00D7", "\\u2208", "\\u2209", "\\u220B", "\\u220C", "\\u2218",
29 "\\u221A", "\\u221B", "\\u2229", "\\u222A", "\\u2260", "\\u2264",
30 "\\u2265", "\\u2286", "\\u2288", "\\u228A", "\\u22C5",
31 "\\b(in|isa)\\b(?!\.?\\()"], "");
22 var delimiters = parserConf.delimiters || /^[;,()[\]{}]/;
32 var delimiters = parserConf.delimiters || /^[;,()[\]{}]/;
23 var identifiers = parserConf.identifiers || /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*!*/;
33 var identifiers = parserConf.identifiers ||
24 var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch", "do"];
34 /^[_A-Za-z\u00A1-\u2217\u2219-\uFFFF][\w\u00A1-\u2217\u2219-\uFFFF]*!*/;
25 var blockClosers = ["end", "else", "elseif", "catch", "finally"];
35
26 var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype'];
36 var chars = wordRegexp([octChar, hexChar, sChar, uChar], "'");
27 var builtinList = ['true', 'false', 'nothing', 'NaN', 'Inf'];
37
38 var openersList = ["begin", "function", "type", "struct", "immutable", "let",
39 "macro", "for", "while", "quote", "if", "else", "elseif", "try",
40 "finally", "catch", "do"];
28
41
29 //var stringPrefixes = new RegExp("^[br]?('|\")")
42 var closersList = ["end", "else", "elseif", "catch", "finally"];
30 var stringPrefixes = /^(`|'|"{3}|([brv]?"))/;
43
31 var keywords = wordRegexp(keywordList);
44 var keywordsList = ["if", "else", "elseif", "while", "for", "begin", "let",
32 var builtins = wordRegexp(builtinList);
45 "end", "do", "try", "catch", "finally", "return", "break", "continue",
33 var openers = wordRegexp(blockOpeners);
46 "global", "local", "const", "export", "import", "importall", "using",
34 var closers = wordRegexp(blockClosers);
47 "function", "where", "macro", "module", "baremodule", "struct", "type",
35 var macro = /^@[_A-Za-z][_A-Za-z0-9]*/;
48 "mutable", "immutable", "quote", "typealias", "abstract", "primitive",
36 var symbol = /^:[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*!*/;
49 "bitstype"];
37 var typeAnnotation = /^::[^.,;"{()=$\s]+({[^}]*}+)*/;
50
51 var builtinsList = ["true", "false", "nothing", "NaN", "Inf"];
52
53 CodeMirror.registerHelper("hintWords", "julia", keywordsList.concat(builtinsList));
54
55 var openers = wordRegexp(openersList);
56 var closers = wordRegexp(closersList);
57 var keywords = wordRegexp(keywordsList);
58 var builtins = wordRegexp(builtinsList);
59
60 var macro = /^@[_A-Za-z][\w]*/;
61 var symbol = /^:[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;
62 var stringPrefixes = /^(`|([_A-Za-z\u00A1-\uFFFF]*"("")?))/;
38
63
39 function inArray(state) {
64 function inArray(state) {
40 var ch = currentScope(state);
65 return (state.nestedArrays > 0);
41 if (ch == '[') {
42 return true;
43 }
66 }
44 return false;
67
68 function inGenerator(state) {
69 return (state.nestedGenerators > 0);
45 }
70 }
46
71
47 function currentScope(state) {
72 function currentScope(state, n) {
48 if (state.scopes.length == 0) {
73 if (typeof(n) === "undefined") { n = 0; }
74 if (state.scopes.length <= n) {
49 return null;
75 return null;
50 }
76 }
51 return state.scopes[state.scopes.length - 1];
77 return state.scopes[state.scopes.length - (n + 1)];
52 }
78 }
53
79
54 // tokenizers
80 // tokenizers
55 function tokenBase(stream, state) {
81 function tokenBase(stream, state) {
56 //Handle multiline comments
82 // Handle multiline comments
57 if (stream.match(/^#=\s*/)) {
83 if (stream.match(/^#=/, false)) {
58 state.scopes.push('#=');
84 state.tokenize = tokenComment;
59 }
85 return state.tokenize(stream, state);
60 if (currentScope(state) == '#=' && stream.match(/^=#/)) {
61 state.scopes.pop();
62 return 'comment';
63 }
64 if (state.scopes.indexOf('#=') >= 0) {
65 if (!stream.match(/.*?(?=(#=|=#))/)) {
66 stream.skipToEnd();
67 }
68 return 'comment';
69 }
86 }
70
87
71 // Handle scope changes
88 // Handle scope changes
@@ -74,14 +91,17 b' CodeMirror.defineMode("julia", function('
74 leavingExpr = false;
91 leavingExpr = false;
75 }
92 }
76 state.leavingExpr = false;
93 state.leavingExpr = false;
94
77 if (leavingExpr) {
95 if (leavingExpr) {
78 if (stream.match(/^'+/)) {
96 if (stream.match(/^'+/)) {
79 return 'operator';
97 return "operator";
80 }
98 }
81 }
99 }
82
100
83 if (stream.match(/^\.{2,3}/)) {
101 if (stream.match(/\.{4,}/)) {
84 return 'operator';
102 return "error";
103 } else if (stream.match(/\.{1,3}/)) {
104 return "operator";
85 }
105 }
86
106
87 if (stream.eatSpace()) {
107 if (stream.eatSpace()) {
@@ -93,105 +113,101 b' CodeMirror.defineMode("julia", function('
93 // Handle single line comments
113 // Handle single line comments
94 if (ch === '#') {
114 if (ch === '#') {
95 stream.skipToEnd();
115 stream.skipToEnd();
96 return 'comment';
116 return "comment";
97 }
117 }
98
118
99 if (ch === '[') {
119 if (ch === '[') {
100 state.scopes.push('[');
120 state.scopes.push('[');
121 state.nestedArrays++;
101 }
122 }
102
123
103 var scope = currentScope(state);
124 if (ch === '(') {
125 state.scopes.push('(');
126 state.nestedGenerators++;
127 }
104
128
105 if (scope == '[' && ch === ']') {
129 if (inArray(state) && ch === ']') {
130 if (currentScope(state) === "if") { state.scopes.pop(); }
131 while (currentScope(state) === "for") { state.scopes.pop(); }
106 state.scopes.pop();
132 state.scopes.pop();
133 state.nestedArrays--;
107 state.leavingExpr = true;
134 state.leavingExpr = true;
108 }
135 }
109
136
110 if (scope == '(' && ch === ')') {
137 if (inGenerator(state) && ch === ')') {
138 if (currentScope(state) === "if") { state.scopes.pop(); }
139 while (currentScope(state) === "for") { state.scopes.pop(); }
111 state.scopes.pop();
140 state.scopes.pop();
141 state.nestedGenerators--;
112 state.leavingExpr = true;
142 state.leavingExpr = true;
113 }
143 }
114
144
145 if (inArray(state)) {
146 if (state.lastToken == "end" && stream.match(/^:/)) {
147 return "operator";
148 }
149 if (stream.match(/^end/)) {
150 return "number";
151 }
152 }
153
115 var match;
154 var match;
116 if (!inArray(state) && (match=stream.match(openers, false))) {
155 if (match = stream.match(openers, false)) {
117 state.scopes.push(match);
156 state.scopes.push(match[0]);
118 }
157 }
119
158
120 if (!inArray(state) && stream.match(closers, false)) {
159 if (stream.match(closers, false)) {
121 state.scopes.pop();
160 state.scopes.pop();
122 }
161 }
123
162
124 if (inArray(state)) {
163 // Handle type annotations
125 if (state.lastToken == 'end' && stream.match(/^:/)) {
164 if (stream.match(/^::(?![:\$])/)) {
126 return 'operator';
165 state.tokenize = tokenAnnotation;
127 }
166 return state.tokenize(stream, state);
128 if (stream.match(/^end/)) {
129 return 'number';
130 }
131 }
167 }
132
168
133 if (stream.match(/^=>/)) {
169 // Handle symbols
134 return 'operator';
170 if (!leavingExpr && stream.match(symbol) ||
171 stream.match(/:([<>]:|<<=?|>>>?=?|->|\/\/|\.{2,3}|[\.\\%*+\-<>!\/^|&]=?|[~\?\$])/)) {
172 return "builtin";
173 }
174
175 // Handle parametric types
176 //if (stream.match(/^{[^}]*}(?=\()/)) {
177 // return "builtin";
178 //}
179
180 // Handle operators and Delimiters
181 if (stream.match(operators)) {
182 return "operator";
135 }
183 }
136
184
137 // Handle Number Literals
185 // Handle Number Literals
138 if (stream.match(/^[0-9\.]/, false)) {
186 if (stream.match(/^\.?\d/, false)) {
139 var imMatcher = RegExp(/^im\b/);
187 var imMatcher = RegExp(/^im\b/);
140 var floatLiteral = false;
188 var numberLiteral = false;
141 // Floats
189 // Floats
142 if (stream.match(/^\d*\.(?!\.)\d+([ef][\+\-]?\d+)?/i)) { floatLiteral = true; }
190 if (stream.match(/^(?:(?:\d[_\d]*)?\.(?!\.)(?:\d[_\d]*)?|\d[_\d]*\.(?!\.)(?:\d[_\d]*))?([Eef][\+\-]?[_\d]+)?/i)) { numberLiteral = true; }
143 if (stream.match(/^\d+\.(?!\.)\d*/)) { floatLiteral = true; }
191 if (stream.match(/^0x\.[0-9a-f_]+p[\+\-]?[_\d]+/i)) { numberLiteral = true; }
144 if (stream.match(/^\.\d+/)) { floatLiteral = true; }
145 if (stream.match(/^0x\.[0-9a-f]+p[\+\-]?\d+/i)) { floatLiteral = true; }
146 if (floatLiteral) {
147 // Float literals may be "imaginary"
148 stream.match(imMatcher);
149 state.leavingExpr = true;
150 return 'number';
151 }
152 // Integers
192 // Integers
153 var intLiteral = false;
193 if (stream.match(/^0x[0-9a-f_]+/i)) { numberLiteral = true; } // Hex
154 // Hex
194 if (stream.match(/^0b[01_]+/i)) { numberLiteral = true; } // Binary
155 if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
195 if (stream.match(/^0o[0-7_]+/i)) { numberLiteral = true; } // Octal
156 // Binary
196 if (stream.match(/^[1-9][_\d]*(e[\+\-]?\d+)?/)) { numberLiteral = true; } // Decimal
157 if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
158 // Octal
159 if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
160 // Decimal
161 if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
162 intLiteral = true;
163 }
164 // Zero by itself with no other piece of number.
197 // Zero by itself with no other piece of number.
165 if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
198 if (stream.match(/^0(?![\dx])/i)) { numberLiteral = true; }
166 if (intLiteral) {
199 if (numberLiteral) {
167 // Integer literals may be "long"
200 // Integer literals may be "long"
168 stream.match(imMatcher);
201 stream.match(imMatcher);
169 state.leavingExpr = true;
202 state.leavingExpr = true;
170 return 'number';
203 return "number";
171 }
204 }
172 }
205 }
173
206
174 if (stream.match(/^<:/)) {
207 // Handle Chars
175 return 'operator';
208 if (stream.match(/^'/)) {
176 }
209 state.tokenize = tokenChar;
177
210 return state.tokenize(stream, state);
178 if (stream.match(typeAnnotation)) {
179 return 'builtin';
180 }
181
182 // Handle symbols
183 if (!leavingExpr && stream.match(symbol) || stream.match(/:\./)) {
184 return 'builtin';
185 }
186
187 // Handle parametric types
188 if (stream.match(/^{[^}]*}(?=\()/)) {
189 return 'builtin';
190 }
191
192 // Handle operators and Delimiters
193 if (stream.match(operators)) {
194 return 'operator';
195 }
211 }
196
212
197 // Handle Strings
213 // Handle Strings
@@ -201,7 +217,7 b' CodeMirror.defineMode("julia", function('
201 }
217 }
202
218
203 if (stream.match(macro)) {
219 if (stream.match(macro)) {
204 return 'meta';
220 return "meta";
205 }
221 }
206
222
207 if (stream.match(delimiters)) {
223 if (stream.match(delimiters)) {
@@ -209,41 +225,40 b' CodeMirror.defineMode("julia", function('
209 }
225 }
210
226
211 if (stream.match(keywords)) {
227 if (stream.match(keywords)) {
212 return 'keyword';
228 return "keyword";
213 }
229 }
214
230
215 if (stream.match(builtins)) {
231 if (stream.match(builtins)) {
216 return 'builtin';
232 return "builtin";
217 }
233 }
218
234
219 var isDefinition = state.isDefinition ||
235 var isDefinition = state.isDefinition || state.lastToken == "function" ||
220 state.lastToken == 'function' ||
236 state.lastToken == "macro" || state.lastToken == "type" ||
221 state.lastToken == 'macro' ||
237 state.lastToken == "struct" || state.lastToken == "immutable";
222 state.lastToken == 'type' ||
223 state.lastToken == 'immutable';
224
238
225 if (stream.match(identifiers)) {
239 if (stream.match(identifiers)) {
226 if (isDefinition) {
240 if (isDefinition) {
227 if (stream.peek() === '.') {
241 if (stream.peek() === '.') {
228 state.isDefinition = true;
242 state.isDefinition = true;
229 return 'variable';
243 return "variable";
230 }
244 }
231 state.isDefinition = false;
245 state.isDefinition = false;
232 return 'def';
246 return "def";
233 }
247 }
234 if (stream.match(/^({[^}]*})*\(/, false)) {
248 if (stream.match(/^({[^}]*})*\(/, false)) {
235 return callOrDef(stream, state);
249 state.tokenize = tokenCallOrDef;
250 return state.tokenize(stream, state);
236 }
251 }
237 state.leavingExpr = true;
252 state.leavingExpr = true;
238 return 'variable';
253 return "variable";
239 }
254 }
240
255
241 // Handle non-detected items
256 // Handle non-detected items
242 stream.next();
257 stream.next();
243 return ERRORCLASS;
258 return "error";
244 }
259 }
245
260
246 function callOrDef(stream, state) {
261 function tokenCallOrDef(stream, state) {
247 var match = stream.match(/^(\(\s*)/);
262 var match = stream.match(/^(\(\s*)/);
248 if (match) {
263 if (match) {
249 if (state.firstParenPos < 0)
264 if (state.firstParenPos < 0)
@@ -255,13 +270,14 b' CodeMirror.defineMode("julia", function('
255 state.scopes.pop();
270 state.scopes.pop();
256 state.charsAdvanced += 1;
271 state.charsAdvanced += 1;
257 if (state.scopes.length <= state.firstParenPos) {
272 if (state.scopes.length <= state.firstParenPos) {
258 var isDefinition = stream.match(/^\s*?=(?!=)/, false);
273 var isDefinition = stream.match(/^(\s*where\s+[^\s=]+)*\s*?=(?!=)/, false);
259 stream.backUp(state.charsAdvanced);
274 stream.backUp(state.charsAdvanced);
260 state.firstParenPos = -1;
275 state.firstParenPos = -1;
261 state.charsAdvanced = 0;
276 state.charsAdvanced = 0;
277 state.tokenize = tokenBase;
262 if (isDefinition)
278 if (isDefinition)
263 return 'def';
279 return "def";
264 return 'builtin';
280 return "builtin";
265 }
281 }
266 }
282 }
267 // Unfortunately javascript does not support multiline strings, so we have
283 // Unfortunately javascript does not support multiline strings, so we have
@@ -269,48 +285,93 b' CodeMirror.defineMode("julia", function('
269 // over two or more lines.
285 // over two or more lines.
270 if (stream.match(/^$/g, false)) {
286 if (stream.match(/^$/g, false)) {
271 stream.backUp(state.charsAdvanced);
287 stream.backUp(state.charsAdvanced);
272 while (state.scopes.length > state.firstParenPos + 1)
288 while (state.scopes.length > state.firstParenPos)
273 state.scopes.pop();
289 state.scopes.pop();
274 state.firstParenPos = -1;
290 state.firstParenPos = -1;
275 state.charsAdvanced = 0;
291 state.charsAdvanced = 0;
276 return 'builtin';
292 state.tokenize = tokenBase;
293 return "builtin";
277 }
294 }
278 state.charsAdvanced += stream.match(/^([^()]*)/)[1].length;
295 state.charsAdvanced += stream.match(/^([^()]*)/)[1].length;
279 return callOrDef(stream, state);
296 return state.tokenize(stream, state);
297 }
298
299 function tokenAnnotation(stream, state) {
300 stream.match(/.*?(?=,|;|{|}|\(|\)|=|$|\s)/);
301 if (stream.match(/^{/)) {
302 state.nestedParameters++;
303 } else if (stream.match(/^}/) && state.nestedParameters > 0) {
304 state.nestedParameters--;
305 }
306 if (state.nestedParameters > 0) {
307 stream.match(/.*?(?={|})/) || stream.next();
308 } else if (state.nestedParameters == 0) {
309 state.tokenize = tokenBase;
310 }
311 return "builtin";
312 }
313
314 function tokenComment(stream, state) {
315 if (stream.match(/^#=/)) {
316 state.nestedComments++;
317 }
318 if (!stream.match(/.*?(?=(#=|=#))/)) {
319 stream.skipToEnd();
320 }
321 if (stream.match(/^=#/)) {
322 state.nestedComments--;
323 if (state.nestedComments == 0)
324 state.tokenize = tokenBase;
325 }
326 return "comment";
327 }
328
329 function tokenChar(stream, state) {
330 var isChar = false, match;
331 if (stream.match(chars)) {
332 isChar = true;
333 } else if (match = stream.match(/\\u([a-f0-9]{1,4})(?=')/i)) {
334 var value = parseInt(match[1], 16);
335 if (value <= 55295 || value >= 57344) { // (U+0,U+D7FF), (U+E000,U+FFFF)
336 isChar = true;
337 stream.next();
338 }
339 } else if (match = stream.match(/\\U([A-Fa-f0-9]{5,8})(?=')/)) {
340 var value = parseInt(match[1], 16);
341 if (value <= 1114111) { // U+10FFFF
342 isChar = true;
343 stream.next();
344 }
345 }
346 if (isChar) {
347 state.leavingExpr = true;
348 state.tokenize = tokenBase;
349 return "string";
350 }
351 if (!stream.match(/^[^']+(?=')/)) { stream.skipToEnd(); }
352 if (stream.match(/^'/)) { state.tokenize = tokenBase; }
353 return "error";
280 }
354 }
281
355
282 function tokenStringFactory(delimiter) {
356 function tokenStringFactory(delimiter) {
283 while ('bruv'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
357 if (delimiter.substr(-3) === '"""') {
284 delimiter = delimiter.substr(1);
358 delimiter = '"""';
359 } else if (delimiter.substr(-1) === '"') {
360 delimiter = '"';
285 }
361 }
286 var singleline = delimiter == "'";
287 var OUTCLASS = 'string';
288
289 function tokenString(stream, state) {
362 function tokenString(stream, state) {
290 while (!stream.eol()) {
291 stream.eatWhile(/[^'"\\]/);
292 if (stream.eat('\\')) {
363 if (stream.eat('\\')) {
293 stream.next();
364 stream.next();
294 if (singleline && stream.eol()) {
295 return OUTCLASS;
296 }
297 } else if (stream.match(delimiter)) {
365 } else if (stream.match(delimiter)) {
298 state.tokenize = tokenBase;
366 state.tokenize = tokenBase;
299 return OUTCLASS;
367 state.leavingExpr = true;
368 return "string";
300 } else {
369 } else {
301 stream.eat(/['"]/);
370 stream.eat(/[`"]/);
302 }
303 }
371 }
304 if (singleline) {
372 stream.eatWhile(/[^\\`"]/);
305 if (parserConf.singleLineStringErrors) {
373 return "string";
306 return ERRORCLASS;
307 } else {
308 state.tokenize = tokenBase;
309 }
374 }
310 }
311 return OUTCLASS;
312 }
313 tokenString.isString = true;
314 return tokenString;
375 return tokenString;
315 }
376 }
316
377
@@ -322,6 +383,10 b' CodeMirror.defineMode("julia", function('
322 lastToken: null,
383 lastToken: null,
323 leavingExpr: false,
384 leavingExpr: false,
324 isDefinition: false,
385 isDefinition: false,
386 nestedArrays: 0,
387 nestedComments: 0,
388 nestedGenerators: 0,
389 nestedParameters: 0,
325 charsAdvanced: 0,
390 charsAdvanced: 0,
326 firstParenPos: -1
391 firstParenPos: -1
327 };
392 };
@@ -335,25 +400,25 b' CodeMirror.defineMode("julia", function('
335 state.lastToken = current;
400 state.lastToken = current;
336 }
401 }
337
402
338 // Handle '.' connected identifiers
339 if (current === '.') {
340 style = stream.match(identifiers, false) || stream.match(macro, false) ||
341 stream.match(/\(/, false) ? 'operator' : ERRORCLASS;
342 }
343 return style;
403 return style;
344 },
404 },
345
405
346 indent: function(state, textAfter) {
406 indent: function(state, textAfter) {
347 var delta = 0;
407 var delta = 0;
348 if (textAfter == "end" || textAfter == "]" || textAfter == "}" || textAfter == "else" || textAfter == "elseif" || textAfter == "catch" || textAfter == "finally") {
408 if ( textAfter === ']' || textAfter === ')' || textAfter === "end" ||
409 textAfter === "else" || textAfter === "catch" || textAfter === "elseif" ||
410 textAfter === "finally" ) {
349 delta = -1;
411 delta = -1;
350 }
412 }
351 return (state.scopes.length + delta) * _conf.indentUnit;
413 return (state.scopes.length + delta) * config.indentUnit;
352 },
414 },
353
415
416 electricInput: /\b(end|else|catch|finally)\b/,
417 blockCommentStart: "#=",
418 blockCommentEnd: "=#",
354 lineComment: "#",
419 lineComment: "#",
355 fold: "indent",
420 closeBrackets: "()[]{}\"\"",
356 electricChars: "edlsifyh]}"
421 fold: "indent"
357 };
422 };
358 return external;
423 return external;
359 });
424 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /**
4 /**
5 * Link to the project's GitHub page:
5 * Link to the project's GitHub page:
@@ -50,7 +50,7 b''
50 startState: function(){
50 startState: function(){
51 return {
51 return {
52 next: 'start',
52 next: 'start',
53 lastToken: null
53 lastToken: {style: null, indent: 0, content: ""}
54 };
54 };
55 },
55 },
56 token: function(stream, state){
56 token: function(stream, state){
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's
4 // LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's
5 // CodeMirror 1 mode.
5 // CodeMirror 1 mode.
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -13,8 +13,8 b''
13
13
14 CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
14 CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
15
15
16 var htmlFound = CodeMirror.modes.hasOwnProperty("xml");
16 var htmlMode = CodeMirror.getMode(cmCfg, "text/html");
17 var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain");
17 var htmlModeMissing = htmlMode.name == "null"
18
18
19 function getMode(name) {
19 function getMode(name) {
20 if (CodeMirror.findModeByName) {
20 if (CodeMirror.findModeByName) {
@@ -35,15 +35,6 b' CodeMirror.defineMode("markdown", functi'
35 if (modeCfg.maxBlockquoteDepth === undefined)
35 if (modeCfg.maxBlockquoteDepth === undefined)
36 modeCfg.maxBlockquoteDepth = 0;
36 modeCfg.maxBlockquoteDepth = 0;
37
37
38 // Should underscores in words open/close em/strong?
39 if (modeCfg.underscoresBreakWords === undefined)
40 modeCfg.underscoresBreakWords = true;
41
42 // Use `fencedCodeBlocks` to configure fenced code blocks. false to
43 // disable, string to specify a precise regexp that the fence should
44 // match, and true to allow three or more backticks or tildes (as
45 // per CommonMark).
46
47 // Turn on task lists? ("- [ ] " and "- [x] ")
38 // Turn on task lists? ("- [ ] " and "- [x] ")
48 if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
39 if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
49
40
@@ -51,12 +42,19 b' CodeMirror.defineMode("markdown", functi'
51 if (modeCfg.strikethrough === undefined)
42 if (modeCfg.strikethrough === undefined)
52 modeCfg.strikethrough = false;
43 modeCfg.strikethrough = false;
53
44
45 if (modeCfg.emoji === undefined)
46 modeCfg.emoji = false;
47
48 if (modeCfg.fencedCodeBlockHighlighting === undefined)
49 modeCfg.fencedCodeBlockHighlighting = true;
50
51 if (modeCfg.xml === undefined)
52 modeCfg.xml = true;
53
54 // Allow token types to be overridden by user-provided token types.
54 // Allow token types to be overridden by user-provided token types.
55 if (modeCfg.tokenTypeOverrides === undefined)
55 if (modeCfg.tokenTypeOverrides === undefined)
56 modeCfg.tokenTypeOverrides = {};
56 modeCfg.tokenTypeOverrides = {};
57
57
58 var codeDepth = 0;
59
60 var tokenTypes = {
58 var tokenTypes = {
61 header: "header",
59 header: "header",
62 code: "comment",
60 code: "comment",
@@ -65,7 +63,9 b' CodeMirror.defineMode("markdown", functi'
65 list2: "variable-3",
63 list2: "variable-3",
66 list3: "keyword",
64 list3: "keyword",
67 hr: "hr",
65 hr: "hr",
68 image: "tag",
66 image: "image",
67 imageAltText: "image-alt-text",
68 imageMarker: "image-marker",
69 formatting: "formatting",
69 formatting: "formatting",
70 linkInline: "link",
70 linkInline: "link",
71 linkEmail: "link",
71 linkEmail: "link",
@@ -73,7 +73,8 b' CodeMirror.defineMode("markdown", functi'
73 linkHref: "string",
73 linkHref: "string",
74 em: "em",
74 em: "em",
75 strong: "strong",
75 strong: "strong",
76 strikethrough: "strikethrough"
76 strikethrough: "strikethrough",
77 emoji: "builtin"
77 };
78 };
78
79
79 for (var tokenType in tokenTypes) {
80 for (var tokenType in tokenTypes) {
@@ -83,14 +84,15 b' CodeMirror.defineMode("markdown", functi'
83 }
84 }
84
85
85 var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/
86 var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/
86 , ulRE = /^[*\-+]\s+/
87 , listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/
87 , olRE = /^[0-9]+([.)])\s+/
88 , taskListRE = /^\[(x| )\](?=\s)/i // Must follow listRE
88 , taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
89 , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/
89 , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/
90 , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/
90 , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/
91 , textRE = /^[^#!\[\]*_\\<>` "'(~]+/
91 , textRE = /^[^#!\[\]*_\\<>` "'(~:]+/
92 , fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) +
92 , fencedCodeRE = /^(~~~+|```+)[ \t]*([\w+#-]*)[^\n`]*$/
93 ")[ \\t]*([\\w+#]*)");
93 , linkDefRE = /^\s*\[[^\]]+?\]:.*$/ // naive link-definition
94 , punctuation = /[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]/
95 , expandedTab = " " // CommonMark specifies tab as 4 spaces
94
96
95 function switchInline(stream, state, f) {
97 function switchInline(stream, state, f) {
96 state.f = state.inline = f;
98 state.f = state.inline = f;
@@ -111,6 +113,8 b' CodeMirror.defineMode("markdown", functi'
111 function blankLine(state) {
113 function blankLine(state) {
112 // Reset linkTitle state
114 // Reset linkTitle state
113 state.linkTitle = false;
115 state.linkTitle = false;
116 state.linkHref = false;
117 state.linkText = false;
114 // Reset EM state
118 // Reset EM state
115 state.em = false;
119 state.em = false;
116 // Reset STRONG state
120 // Reset STRONG state
@@ -121,102 +125,154 b' CodeMirror.defineMode("markdown", functi'
121 state.quote = 0;
125 state.quote = 0;
122 // Reset state.indentedCode
126 // Reset state.indentedCode
123 state.indentedCode = false;
127 state.indentedCode = false;
124 if (!htmlFound && state.f == htmlBlock) {
128 if (state.f == htmlBlock) {
129 var exit = htmlModeMissing
130 if (!exit) {
131 var inner = CodeMirror.innerMode(htmlMode, state.htmlState)
132 exit = inner.mode.name == "xml" && inner.state.tagStart === null &&
133 (!inner.state.context && inner.state.tokenize.isInText)
134 }
135 if (exit) {
125 state.f = inlineNormal;
136 state.f = inlineNormal;
126 state.block = blockNormal;
137 state.block = blockNormal;
138 state.htmlState = null;
139 }
127 }
140 }
128 // Reset state.trailingSpace
141 // Reset state.trailingSpace
129 state.trailingSpace = 0;
142 state.trailingSpace = 0;
130 state.trailingSpaceNewLine = false;
143 state.trailingSpaceNewLine = false;
131 // Mark this line as blank
144 // Mark this line as blank
132 state.prevLine = state.thisLine
145 state.prevLine = state.thisLine
133 state.thisLine = null
146 state.thisLine = {stream: null}
134 return null;
147 return null;
135 }
148 }
136
149
137 function blockNormal(stream, state) {
150 function blockNormal(stream, state) {
138
151 var firstTokenOnLine = stream.column() === state.indentation;
139 var sol = stream.sol();
152 var prevLineLineIsEmpty = lineIsEmpty(state.prevLine.stream);
140
153 var prevLineIsIndentedCode = state.indentedCode;
141 var prevLineIsList = state.list !== false,
154 var prevLineIsHr = state.prevLine.hr;
142 prevLineIsIndentedCode = state.indentedCode;
155 var prevLineIsList = state.list !== false;
156 var maxNonCodeIndentation = (state.listStack[state.listStack.length - 1] || 0) + 3;
143
157
144 state.indentedCode = false;
158 state.indentedCode = false;
145
159
160 var lineIndentation = state.indentation;
161 // compute once per line (on first token)
162 if (state.indentationDiff === null) {
163 state.indentationDiff = state.indentation;
146 if (prevLineIsList) {
164 if (prevLineIsList) {
147 if (state.indentationDiff >= 0) { // Continued list
148 if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
149 state.indentation -= state.indentationDiff;
150 }
151 state.list = null;
165 state.list = null;
152 } else if (state.indentation > 0) {
166 // While this list item's marker's indentation is less than the deepest
153 state.list = null;
167 // list item's content's indentation,pop the deepest list item
154 state.listDepth = Math.floor(state.indentation / 4);
168 // indentation off the stack, and update block indentation state
155 } else { // No longer a list
169 while (lineIndentation < state.listStack[state.listStack.length - 1]) {
170 state.listStack.pop();
171 if (state.listStack.length) {
172 state.indentation = state.listStack[state.listStack.length - 1];
173 // less than the first list's indent -> the line is no longer a list
174 } else {
156 state.list = false;
175 state.list = false;
157 state.listDepth = 0;
176 }
177 }
178 if (state.list !== false) {
179 state.indentationDiff = lineIndentation - state.listStack[state.listStack.length - 1]
180 }
158 }
181 }
159 }
182 }
160
183
184 // not comprehensive (currently only for setext detection purposes)
185 var allowsInlineContinuation = (
186 !prevLineLineIsEmpty && !prevLineIsHr && !state.prevLine.header &&
187 (!prevLineIsList || !prevLineIsIndentedCode) &&
188 !state.prevLine.fencedCodeEnd
189 );
190
191 var isHr = (state.list === false || prevLineIsHr || prevLineLineIsEmpty) &&
192 state.indentation <= maxNonCodeIndentation && stream.match(hrRE);
193
161 var match = null;
194 var match = null;
162 if (state.indentationDiff >= 4) {
195 if (state.indentationDiff >= 4 && (prevLineIsIndentedCode || state.prevLine.fencedCodeEnd ||
196 state.prevLine.header || prevLineLineIsEmpty)) {
163 stream.skipToEnd();
197 stream.skipToEnd();
164 if (prevLineIsIndentedCode || lineIsEmpty(state.prevLine)) {
165 state.indentation -= 4;
166 state.indentedCode = true;
198 state.indentedCode = true;
167 return tokenTypes.code;
199 return tokenTypes.code;
168 } else {
169 return null;
170 }
171 } else if (stream.eatSpace()) {
200 } else if (stream.eatSpace()) {
172 return null;
201 return null;
173 } else if ((match = stream.match(atxHeaderRE)) && match[1].length <= 6) {
202 } else if (firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(atxHeaderRE)) && match[1].length <= 6) {
203 state.quote = 0;
174 state.header = match[1].length;
204 state.header = match[1].length;
205 state.thisLine.header = true;
175 if (modeCfg.highlightFormatting) state.formatting = "header";
206 if (modeCfg.highlightFormatting) state.formatting = "header";
176 state.f = state.inline;
207 state.f = state.inline;
177 return getType(state);
208 return getType(state);
178 } else if (!lineIsEmpty(state.prevLine) && !state.quote && !prevLineIsList &&
209 } else if (state.indentation <= maxNonCodeIndentation && stream.eat('>')) {
179 !prevLineIsIndentedCode && (match = stream.match(setextHeaderRE))) {
210 state.quote = firstTokenOnLine ? 1 : state.quote + 1;
180 state.header = match[0].charAt(0) == '=' ? 1 : 2;
181 if (modeCfg.highlightFormatting) state.formatting = "header";
182 state.f = state.inline;
183 return getType(state);
184 } else if (stream.eat('>')) {
185 state.quote = sol ? 1 : state.quote + 1;
186 if (modeCfg.highlightFormatting) state.formatting = "quote";
211 if (modeCfg.highlightFormatting) state.formatting = "quote";
187 stream.eatSpace();
212 stream.eatSpace();
188 return getType(state);
213 return getType(state);
189 } else if (stream.peek() === '[') {
214 } else if (!isHr && !state.setext && firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(listRE))) {
190 return switchInline(stream, state, footnoteLink);
215 var listType = match[1] ? "ol" : "ul";
191 } else if (stream.match(hrRE, true)) {
216
192 state.hr = true;
217 state.indentation = lineIndentation + stream.current().length;
193 return tokenTypes.hr;
194 } else if ((lineIsEmpty(state.prevLine) || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) {
195 var listType = null;
196 if (stream.match(ulRE, true)) {
197 listType = 'ul';
198 } else {
199 stream.match(olRE, true);
200 listType = 'ol';
201 }
202 state.indentation = stream.column() + stream.current().length;
203 state.list = true;
218 state.list = true;
204 state.listDepth++;
219 state.quote = 0;
220
221 // Add this list item's content's indentation to the stack
222 state.listStack.push(state.indentation);
223 // Reset inline styles which shouldn't propagate aross list items
224 state.em = false;
225 state.strong = false;
226 state.code = false;
227 state.strikethrough = false;
228
205 if (modeCfg.taskLists && stream.match(taskListRE, false)) {
229 if (modeCfg.taskLists && stream.match(taskListRE, false)) {
206 state.taskList = true;
230 state.taskList = true;
207 }
231 }
208 state.f = state.inline;
232 state.f = state.inline;
209 if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
233 if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
210 return getType(state);
234 return getType(state);
211 } else if (modeCfg.fencedCodeBlocks && (match = stream.match(fencedCodeRE, true))) {
235 } else if (firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(fencedCodeRE, true))) {
212 state.fencedChars = match[1]
236 state.quote = 0;
237 state.fencedEndRE = new RegExp(match[1] + "+ *$");
213 // try switching mode
238 // try switching mode
214 state.localMode = getMode(match[2]);
239 state.localMode = modeCfg.fencedCodeBlockHighlighting && getMode(match[2]);
215 if (state.localMode) state.localState = state.localMode.startState();
240 if (state.localMode) state.localState = CodeMirror.startState(state.localMode);
216 state.f = state.block = local;
241 state.f = state.block = local;
217 if (modeCfg.highlightFormatting) state.formatting = "code-block";
242 if (modeCfg.highlightFormatting) state.formatting = "code-block";
218 state.code = true;
243 state.code = -1
219 return getType(state);
244 return getType(state);
245 // SETEXT has lowest block-scope precedence after HR, so check it after
246 // the others (code, blockquote, list...)
247 } else if (
248 // if setext set, indicates line after ---/===
249 state.setext || (
250 // line before ---/===
251 (!allowsInlineContinuation || !prevLineIsList) && !state.quote && state.list === false &&
252 !state.code && !isHr && !linkDefRE.test(stream.string) &&
253 (match = stream.lookAhead(1)) && (match = match.match(setextHeaderRE))
254 )
255 ) {
256 if ( !state.setext ) {
257 state.header = match[0].charAt(0) == '=' ? 1 : 2;
258 state.setext = state.header;
259 } else {
260 state.header = state.setext;
261 // has no effect on type so we can reset it now
262 state.setext = 0;
263 stream.skipToEnd();
264 if (modeCfg.highlightFormatting) state.formatting = "header";
265 }
266 state.thisLine.header = true;
267 state.f = state.inline;
268 return getType(state);
269 } else if (isHr) {
270 stream.skipToEnd();
271 state.hr = true;
272 state.thisLine.hr = true;
273 return tokenTypes.hr;
274 } else if (stream.peek() === '[') {
275 return switchInline(stream, state, footnoteLink);
220 }
276 }
221
277
222 return switchInline(stream, state, state.inline);
278 return switchInline(stream, state, state.inline);
@@ -224,21 +280,35 b' CodeMirror.defineMode("markdown", functi'
224
280
225 function htmlBlock(stream, state) {
281 function htmlBlock(stream, state) {
226 var style = htmlMode.token(stream, state.htmlState);
282 var style = htmlMode.token(stream, state.htmlState);
227 if ((htmlFound && state.htmlState.tagStart === null &&
283 if (!htmlModeMissing) {
228 (!state.htmlState.context && state.htmlState.tokenize.isInText)) ||
284 var inner = CodeMirror.innerMode(htmlMode, state.htmlState)
285 if ((inner.mode.name == "xml" && inner.state.tagStart === null &&
286 (!inner.state.context && inner.state.tokenize.isInText)) ||
229 (state.md_inside && stream.current().indexOf(">") > -1)) {
287 (state.md_inside && stream.current().indexOf(">") > -1)) {
230 state.f = inlineNormal;
288 state.f = inlineNormal;
231 state.block = blockNormal;
289 state.block = blockNormal;
232 state.htmlState = null;
290 state.htmlState = null;
233 }
291 }
292 }
234 return style;
293 return style;
235 }
294 }
236
295
237 function local(stream, state) {
296 function local(stream, state) {
238 if (state.fencedChars && stream.match(state.fencedChars, false)) {
297 var currListInd = state.listStack[state.listStack.length - 1] || 0;
298 var hasExitedList = state.indentation < currListInd;
299 var maxFencedEndInd = currListInd + 3;
300 if (state.fencedEndRE && state.indentation <= maxFencedEndInd && (hasExitedList || stream.match(state.fencedEndRE))) {
301 if (modeCfg.highlightFormatting) state.formatting = "code-block";
302 var returnType;
303 if (!hasExitedList) returnType = getType(state)
239 state.localMode = state.localState = null;
304 state.localMode = state.localState = null;
240 state.f = state.block = leavingLocal;
305 state.block = blockNormal;
241 return null;
306 state.f = inlineNormal;
307 state.fencedEndRE = null;
308 state.code = 0
309 state.thisLine.fencedCodeEnd = true;
310 if (hasExitedList) return switchBlock(stream, state, state.block);
311 return returnType;
242 } else if (state.localMode) {
312 } else if (state.localMode) {
243 return state.localMode.token(stream, state.localState);
313 return state.localMode.token(stream, state.localState);
244 } else {
314 } else {
@@ -247,18 +317,6 b' CodeMirror.defineMode("markdown", functi'
247 }
317 }
248 }
318 }
249
319
250 function leavingLocal(stream, state) {
251 stream.match(state.fencedChars);
252 state.block = blockNormal;
253 state.f = inlineNormal;
254 state.fencedChars = null;
255 if (modeCfg.highlightFormatting) state.formatting = "code-block";
256 state.code = true;
257 var returnType = getType(state);
258 state.code = false;
259 return returnType;
260 }
261
262 // Inline
320 // Inline
263 function getType(state) {
321 function getType(state) {
264 var styles = [];
322 var styles = [];
@@ -302,8 +360,12 b' CodeMirror.defineMode("markdown", functi'
302 if (state.strong) { styles.push(tokenTypes.strong); }
360 if (state.strong) { styles.push(tokenTypes.strong); }
303 if (state.em) { styles.push(tokenTypes.em); }
361 if (state.em) { styles.push(tokenTypes.em); }
304 if (state.strikethrough) { styles.push(tokenTypes.strikethrough); }
362 if (state.strikethrough) { styles.push(tokenTypes.strikethrough); }
363 if (state.emoji) { styles.push(tokenTypes.emoji); }
305 if (state.linkText) { styles.push(tokenTypes.linkText); }
364 if (state.linkText) { styles.push(tokenTypes.linkText); }
306 if (state.code) { styles.push(tokenTypes.code); }
365 if (state.code) { styles.push(tokenTypes.code); }
366 if (state.image) { styles.push(tokenTypes.image); }
367 if (state.imageAltText) { styles.push(tokenTypes.imageAltText, "link"); }
368 if (state.imageMarker) { styles.push(tokenTypes.imageMarker); }
307 }
369 }
308
370
309 if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); }
371 if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); }
@@ -320,7 +382,7 b' CodeMirror.defineMode("markdown", functi'
320 }
382 }
321
383
322 if (state.list !== false) {
384 if (state.list !== false) {
323 var listMod = (state.listDepth - 1) % 3;
385 var listMod = (state.listStack.length - 1) % 3;
324 if (!listMod) {
386 if (!listMod) {
325 styles.push(tokenTypes.list1);
387 styles.push(tokenTypes.list1);
326 } else if (listMod === 1) {
388 } else if (listMod === 1) {
@@ -357,7 +419,7 b' CodeMirror.defineMode("markdown", functi'
357 }
419 }
358
420
359 if (state.taskList) {
421 if (state.taskList) {
360 var taskOpen = stream.match(taskListRE, true)[1] !== "x";
422 var taskOpen = stream.match(taskListRE, true)[1] === " ";
361 if (taskOpen) state.taskOpen = true;
423 if (taskOpen) state.taskOpen = true;
362 else state.taskClosed = true;
424 else state.taskClosed = true;
363 if (modeCfg.highlightFormatting) state.formatting = "task";
425 if (modeCfg.highlightFormatting) state.formatting = "task";
@@ -373,20 +435,8 b' CodeMirror.defineMode("markdown", functi'
373 return getType(state);
435 return getType(state);
374 }
436 }
375
437
376 // Get sol() value now, before character is consumed
377 var sol = stream.sol();
378
379 var ch = stream.next();
438 var ch = stream.next();
380
439
381 if (ch === '\\') {
382 stream.next();
383 if (modeCfg.highlightFormatting) {
384 var type = getType(state);
385 var formattingEscape = tokenTypes.formatting + "-escape";
386 return type ? type + " " + formattingEscape : formattingEscape;
387 }
388 }
389
390 // Matches link titles present on next line
440 // Matches link titles present on next line
391 if (state.linkTitle) {
441 if (state.linkTitle) {
392 state.linkTitle = false;
442 state.linkTitle = false;
@@ -394,7 +444,7 b' CodeMirror.defineMode("markdown", functi'
394 if (ch === '(') {
444 if (ch === '(') {
395 matchCh = ')';
445 matchCh = ')';
396 }
446 }
397 matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
447 matchCh = (matchCh+'').replace(/([.?*+^\[\]\\(){}|-])/g, "\\$1");
398 var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
448 var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
399 if (stream.match(new RegExp(regex), true)) {
449 if (stream.match(new RegExp(regex), true)) {
400 return tokenTypes.linkHref;
450 return tokenTypes.linkHref;
@@ -405,43 +455,67 b' CodeMirror.defineMode("markdown", functi'
405 if (ch === '`') {
455 if (ch === '`') {
406 var previousFormatting = state.formatting;
456 var previousFormatting = state.formatting;
407 if (modeCfg.highlightFormatting) state.formatting = "code";
457 if (modeCfg.highlightFormatting) state.formatting = "code";
408 var t = getType(state);
409 var before = stream.pos;
410 stream.eatWhile('`');
458 stream.eatWhile('`');
411 var difference = 1 + stream.pos - before;
459 var count = stream.current().length
412 if (!state.code) {
460 if (state.code == 0 && (!state.quote || count == 1)) {
413 codeDepth = difference;
461 state.code = count
414 state.code = true;
462 return getType(state)
415 return getType(state);
463 } else if (count == state.code) { // Must be exact
464 var t = getType(state)
465 state.code = 0
466 return t
416 } else {
467 } else {
417 if (difference === codeDepth) { // Must be exact
468 state.formatting = previousFormatting
418 state.code = false;
469 return getType(state)
419 return t;
420 }
421 state.formatting = previousFormatting;
422 return getType(state);
423 }
470 }
424 } else if (state.code) {
471 } else if (state.code) {
425 return getType(state);
472 return getType(state);
426 }
473 }
427
474
475 if (ch === '\\') {
476 stream.next();
477 if (modeCfg.highlightFormatting) {
478 var type = getType(state);
479 var formattingEscape = tokenTypes.formatting + "-escape";
480 return type ? type + " " + formattingEscape : formattingEscape;
481 }
482 }
483
428 if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
484 if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
429 stream.match(/\[[^\]]*\]/);
485 state.imageMarker = true;
430 state.inline = state.f = linkHref;
486 state.image = true;
431 return tokenTypes.image;
487 if (modeCfg.highlightFormatting) state.formatting = "image";
488 return getType(state);
432 }
489 }
433
490
434 if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) {
491 if (ch === '[' && state.imageMarker && stream.match(/[^\]]*\](\(.*?\)| ?\[.*?\])/, false)) {
492 state.imageMarker = false;
493 state.imageAltText = true
494 if (modeCfg.highlightFormatting) state.formatting = "image";
495 return getType(state);
496 }
497
498 if (ch === ']' && state.imageAltText) {
499 if (modeCfg.highlightFormatting) state.formatting = "image";
500 var type = getType(state);
501 state.imageAltText = false;
502 state.image = false;
503 state.inline = state.f = linkHref;
504 return type;
505 }
506
507 if (ch === '[' && !state.image) {
508 if (state.linkText && stream.match(/^.*?\]/)) return getType(state)
435 state.linkText = true;
509 state.linkText = true;
436 if (modeCfg.highlightFormatting) state.formatting = "link";
510 if (modeCfg.highlightFormatting) state.formatting = "link";
437 return getType(state);
511 return getType(state);
438 }
512 }
439
513
440 if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) {
514 if (ch === ']' && state.linkText) {
441 if (modeCfg.highlightFormatting) state.formatting = "link";
515 if (modeCfg.highlightFormatting) state.formatting = "link";
442 var type = getType(state);
516 var type = getType(state);
443 state.linkText = false;
517 state.linkText = false;
444 state.inline = state.f = linkHref;
518 state.inline = state.f = stream.match(/\(.*?\)| ?\[.*?\]/, false) ? linkHref : inlineNormal
445 return type;
519 return type;
446 }
520 }
447
521
@@ -469,7 +543,7 b' CodeMirror.defineMode("markdown", functi'
469 return type + tokenTypes.linkEmail;
543 return type + tokenTypes.linkEmail;
470 }
544 }
471
545
472 if (ch === '<' && stream.match(/^(!--|\w)/, false)) {
546 if (modeCfg.xml && ch === '<' && stream.match(/^(!--|\?|!\[CDATA\[|[a-z][a-z0-9-]*(?:\s+[a-z_:.\-]+(?:\s*=\s*[^>]+)?)*\s*(?:>|$))/i, false)) {
473 var end = stream.string.indexOf(">", stream.pos);
547 var end = stream.string.indexOf(">", stream.pos);
474 if (end != -1) {
548 if (end != -1) {
475 var atts = stream.string.substring(stream.start, end);
549 var atts = stream.string.substring(stream.start, end);
@@ -480,44 +554,37 b' CodeMirror.defineMode("markdown", functi'
480 return switchBlock(stream, state, htmlBlock);
554 return switchBlock(stream, state, htmlBlock);
481 }
555 }
482
556
483 if (ch === '<' && stream.match(/^\/\w*?>/)) {
557 if (modeCfg.xml && ch === '<' && stream.match(/^\/\w*?>/)) {
484 state.md_inside = false;
558 state.md_inside = false;
485 return "tag";
559 return "tag";
486 }
560 } else if (ch === "*" || ch === "_") {
487
561 var len = 1, before = stream.pos == 1 ? " " : stream.string.charAt(stream.pos - 2)
488 var ignoreUnderscore = false;
562 while (len < 3 && stream.eat(ch)) len++
489 if (!modeCfg.underscoresBreakWords) {
563 var after = stream.peek() || " "
490 if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
564 // See http://spec.commonmark.org/0.27/#emphasis-and-strong-emphasis
491 var prevPos = stream.pos - 2;
565 var leftFlanking = !/\s/.test(after) && (!punctuation.test(after) || /\s/.test(before) || punctuation.test(before))
492 if (prevPos >= 0) {
566 var rightFlanking = !/\s/.test(before) && (!punctuation.test(before) || /\s/.test(after) || punctuation.test(after))
493 var prevCh = stream.string.charAt(prevPos);
567 var setEm = null, setStrong = null
494 if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
568 if (len % 2) { // Em
495 ignoreUnderscore = true;
569 if (!state.em && leftFlanking && (ch === "*" || !rightFlanking || punctuation.test(before)))
496 }
570 setEm = true
497 }
571 else if (state.em == ch && rightFlanking && (ch === "*" || !leftFlanking || punctuation.test(after)))
498 }
572 setEm = false
499 }
573 }
500 if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
574 if (len > 1) { // Strong
501 if (sol && stream.peek() === ' ') {
575 if (!state.strong && leftFlanking && (ch === "*" || !rightFlanking || punctuation.test(before)))
502 // Do nothing, surrounded by newline and space
576 setStrong = true
503 } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
577 else if (state.strong == ch && rightFlanking && (ch === "*" || !leftFlanking || punctuation.test(after)))
504 if (modeCfg.highlightFormatting) state.formatting = "strong";
578 setStrong = false
505 var t = getType(state);
579 }
506 state.strong = false;
580 if (setStrong != null || setEm != null) {
507 return t;
581 if (modeCfg.highlightFormatting) state.formatting = setEm == null ? "strong" : setStrong == null ? "em" : "strong em"
508 } else if (!state.strong && stream.eat(ch)) { // Add STRONG
582 if (setEm === true) state.em = ch
509 state.strong = ch;
583 if (setStrong === true) state.strong = ch
510 if (modeCfg.highlightFormatting) state.formatting = "strong";
584 var t = getType(state)
511 return getType(state);
585 if (setEm === false) state.em = false
512 } else if (state.em === ch) { // Remove EM
586 if (setStrong === false) state.strong = false
513 if (modeCfg.highlightFormatting) state.formatting = "em";
587 return t
514 var t = getType(state);
515 state.em = false;
516 return t;
517 } else if (!state.em) { // Add EM
518 state.em = ch;
519 if (modeCfg.highlightFormatting) state.formatting = "em";
520 return getType(state);
521 }
588 }
522 } else if (ch === ' ') {
589 } else if (ch === ' ') {
523 if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
590 if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
@@ -552,8 +619,16 b' CodeMirror.defineMode("markdown", functi'
552 }
619 }
553 }
620 }
554
621
622 if (modeCfg.emoji && ch === ":" && stream.match(/^(?:[a-z_\d+][a-z_\d+-]*|\-[a-z_\d+][a-z_\d+-]*):/)) {
623 state.emoji = true;
624 if (modeCfg.highlightFormatting) state.formatting = "emoji";
625 var retType = getType(state);
626 state.emoji = false;
627 return retType;
628 }
629
555 if (ch === ' ') {
630 if (ch === ' ') {
556 if (stream.match(/ +$/, false)) {
631 if (stream.match(/^ +$/, false)) {
557 state.trailingSpace++;
632 state.trailingSpace++;
558 } else if (state.trailingSpace) {
633 } else if (state.trailingSpace) {
559 state.trailingSpaceNewLine = true;
634 state.trailingSpaceNewLine = true;
@@ -598,6 +673,11 b' CodeMirror.defineMode("markdown", functi'
598 return 'error';
673 return 'error';
599 }
674 }
600
675
676 var linkRE = {
677 ")": /^(?:[^\\\(\)]|\\.|\((?:[^\\\(\)]|\\.)*\))*?(?=\))/,
678 "]": /^(?:[^\\\[\]]|\\.|\[(?:[^\\\[\]]|\\.)*\])*?(?=\])/
679 }
680
601 function getLinkHrefInside(endChar) {
681 function getLinkHrefInside(endChar) {
602 return function(stream, state) {
682 return function(stream, state) {
603 var ch = stream.next();
683 var ch = stream.next();
@@ -610,10 +690,7 b' CodeMirror.defineMode("markdown", functi'
610 return returnState;
690 return returnState;
611 }
691 }
612
692
613 if (stream.match(inlineRE(endChar), true)) {
693 stream.match(linkRE[endChar])
614 stream.backUp(1);
615 }
616
617 state.linkHref = true;
694 state.linkHref = true;
618 return getType(state);
695 return getType(state);
619 };
696 };
@@ -661,25 +738,13 b' CodeMirror.defineMode("markdown", functi'
661 return tokenTypes.linkHref + " url";
738 return tokenTypes.linkHref + " url";
662 }
739 }
663
740
664 var savedInlineRE = [];
665 function inlineRE(endChar) {
666 if (!savedInlineRE[endChar]) {
667 // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
668 endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
669 // Match any non-endChar, escaped character, as well as the closing
670 // endChar.
671 savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
672 }
673 return savedInlineRE[endChar];
674 }
675
676 var mode = {
741 var mode = {
677 startState: function() {
742 startState: function() {
678 return {
743 return {
679 f: blockNormal,
744 f: blockNormal,
680
745
681 prevLine: null,
746 prevLine: {stream: null},
682 thisLine: null,
747 thisLine: {stream: null},
683
748
684 block: blockNormal,
749 block: blockNormal,
685 htmlState: null,
750 htmlState: null,
@@ -692,18 +757,21 b' CodeMirror.defineMode("markdown", functi'
692 linkText: false,
757 linkText: false,
693 linkHref: false,
758 linkHref: false,
694 linkTitle: false,
759 linkTitle: false,
760 code: 0,
695 em: false,
761 em: false,
696 strong: false,
762 strong: false,
697 header: 0,
763 header: 0,
764 setext: 0,
698 hr: false,
765 hr: false,
699 taskList: false,
766 taskList: false,
700 list: false,
767 list: false,
701 listDepth: 0,
768 listStack: [],
702 quote: 0,
769 quote: 0,
703 trailingSpace: 0,
770 trailingSpace: 0,
704 trailingSpaceNewLine: false,
771 trailingSpaceNewLine: false,
705 strikethrough: false,
772 strikethrough: false,
706 fencedChars: null
773 emoji: false,
774 fencedEndRE: null
707 };
775 };
708 },
776 },
709
777
@@ -724,22 +792,26 b' CodeMirror.defineMode("markdown", functi'
724 inline: s.inline,
792 inline: s.inline,
725 text: s.text,
793 text: s.text,
726 formatting: false,
794 formatting: false,
795 linkText: s.linkText,
727 linkTitle: s.linkTitle,
796 linkTitle: s.linkTitle,
797 linkHref: s.linkHref,
728 code: s.code,
798 code: s.code,
729 em: s.em,
799 em: s.em,
730 strong: s.strong,
800 strong: s.strong,
731 strikethrough: s.strikethrough,
801 strikethrough: s.strikethrough,
802 emoji: s.emoji,
732 header: s.header,
803 header: s.header,
804 setext: s.setext,
733 hr: s.hr,
805 hr: s.hr,
734 taskList: s.taskList,
806 taskList: s.taskList,
735 list: s.list,
807 list: s.list,
736 listDepth: s.listDepth,
808 listStack: s.listStack.slice(0),
737 quote: s.quote,
809 quote: s.quote,
738 indentedCode: s.indentedCode,
810 indentedCode: s.indentedCode,
739 trailingSpace: s.trailingSpace,
811 trailingSpace: s.trailingSpace,
740 trailingSpaceNewLine: s.trailingSpaceNewLine,
812 trailingSpaceNewLine: s.trailingSpaceNewLine,
741 md_inside: s.md_inside,
813 md_inside: s.md_inside,
742 fencedChars: s.fencedChars
814 fencedEndRE: s.fencedEndRE
743 };
815 };
744 },
816 },
745
817
@@ -748,21 +820,17 b' CodeMirror.defineMode("markdown", functi'
748 // Reset state.formatting
820 // Reset state.formatting
749 state.formatting = false;
821 state.formatting = false;
750
822
751 if (stream != state.thisLine) {
823 if (stream != state.thisLine.stream) {
752 var forceBlankLine = state.header || state.hr;
753
754 // Reset state.header and state.hr
755 state.header = 0;
824 state.header = 0;
756 state.hr = false;
825 state.hr = false;
757
826
758 if (stream.match(/^\s*$/, true) || forceBlankLine) {
827 if (stream.match(/^\s*$/, true)) {
759 blankLine(state);
828 blankLine(state);
760 if (!forceBlankLine) return null
829 return null;
761 state.prevLine = null
762 }
830 }
763
831
764 state.prevLine = state.thisLine
832 state.prevLine = state.thisLine
765 state.thisLine = stream
833 state.thisLine = {stream: stream}
766
834
767 // Reset state.taskList
835 // Reset state.taskList
768 state.taskList = false;
836 state.taskList = false;
@@ -771,15 +839,16 b' CodeMirror.defineMode("markdown", functi'
771 state.trailingSpace = 0;
839 state.trailingSpace = 0;
772 state.trailingSpaceNewLine = false;
840 state.trailingSpaceNewLine = false;
773
841
842 if (!state.localState) {
774 state.f = state.block;
843 state.f = state.block;
775 var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
844 if (state.f != htmlBlock) {
776 var difference = Math.floor((indentation - state.indentation) / 4) * 4;
845 var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, expandedTab).length;
777 if (difference > 4) difference = 4;
846 state.indentation = indentation;
778 var adjustedIndentation = state.indentation + difference;
847 state.indentationDiff = null;
779 state.indentationDiff = adjustedIndentation - state.indentation;
780 state.indentation = adjustedIndentation;
781 if (indentation > 0) return null;
848 if (indentation > 0) return null;
782 }
849 }
850 }
851 }
783 return state.f(stream, state);
852 return state.f(stream, state);
784 },
853 },
785
854
@@ -789,15 +858,26 b' CodeMirror.defineMode("markdown", functi'
789 return {state: state, mode: mode};
858 return {state: state, mode: mode};
790 },
859 },
791
860
861 indent: function(state, textAfter, line) {
862 if (state.block == htmlBlock && htmlMode.indent) return htmlMode.indent(state.htmlState, textAfter, line)
863 if (state.localState && state.localMode.indent) return state.localMode.indent(state.localState, textAfter, line)
864 return CodeMirror.Pass
865 },
866
792 blankLine: blankLine,
867 blankLine: blankLine,
793
868
794 getType: getType,
869 getType: getType,
795
870
871 blockCommentStart: "<!--",
872 blockCommentEnd: "-->",
873 closeBrackets: "()[]{}''\"\"``",
796 fold: "markdown"
874 fold: "markdown"
797 };
875 };
798 return mode;
876 return mode;
799 }, "xml");
877 }, "xml");
800
878
879 CodeMirror.defineMIME("text/markdown", "markdown");
880
801 CodeMirror.defineMIME("text/x-markdown", "markdown");
881 CodeMirror.defineMIME("text/x-markdown", "markdown");
802
882
803 });
883 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Mathematica mode copyright (c) 2015 by Calin Barbat
4 // Mathematica mode copyright (c) 2015 by Calin Barbat
5 // Based on code by Patrick Scheibe (halirutan)
5 // Based on code by Patrick Scheibe (halirutan)
@@ -71,12 +71,12 b" CodeMirror.defineMode('mathematica', fun"
71 }
71 }
72
72
73 // usage
73 // usage
74 if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::usage)/, true, false)) {
74 if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*(?:`[a-zA-Z0-9\$]+)*::usage)/, true, false)) {
75 return 'meta';
75 return 'meta';
76 }
76 }
77
77
78 // message
78 // message
79 if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::[a-zA-Z\$][a-zA-Z0-9\$]*):?/, true, false)) {
79 if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*(?:`[a-zA-Z0-9\$]+)*::[a-zA-Z\$][a-zA-Z0-9\$]*):?/, true, false)) {
80 return 'string-2';
80 return 'string-2';
81 }
81 }
82
82
@@ -126,6 +126,7 b" CodeMirror.defineMode('mathematica', fun"
126 }
126 }
127
127
128 // everything else is an error
128 // everything else is an error
129 stream.next(); // advance the stream.
129 return 'error';
130 return 'error';
130 }
131 }
131
132
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -13,19 +13,19 b''
13
13
14 CodeMirror.modeInfo = [
14 CodeMirror.modeInfo = [
15 {name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]},
15 {name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]},
16 {name: "PGP", mimes: ["application/pgp", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["pgp"]},
16 {name: "PGP", mimes: ["application/pgp", "application/pgp-encrypted", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["asc", "pgp", "sig"]},
17 {name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]},
17 {name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]},
18 {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i},
18 {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i},
19 {name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]},
19 {name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]},
20 {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]},
20 {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h", "ino"]},
21 {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
21 {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
22 {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
22 {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
23 {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]},
23 {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp", "cs"]},
24 {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]},
24 {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]},
25 {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]},
25 {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]},
26 {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
26 {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
27 {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/},
27 {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/},
28 {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
28 {name: "CoffeeScript", mimes: ["application/vnd.coffeescript", "text/coffeescript", "text/x-coffeescript"], mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
29 {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]},
29 {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]},
30 {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]},
30 {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]},
31 {name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]},
31 {name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]},
@@ -41,30 +41,33 b''
41 {name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
41 {name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
42 {name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"},
42 {name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"},
43 {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
43 {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
44 {name: "edn", mime: "application/edn", mode: "clojure", ext: ["edn"]},
44 {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
45 {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
45 {name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]},
46 {name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]},
46 {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
47 {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
47 {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]},
48 {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]},
48 {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
49 {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
50 {name: "Esper", mime: "text/x-esper", mode: "sql"},
49 {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},
51 {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},
52 {name: "FCL", mime: "text/x-fcl", mode: "fcl"},
50 {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]},
53 {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]},
51 {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]},
54 {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90", "f95"]},
52 {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
55 {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
53 {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
56 {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
54 {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
57 {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
55 {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i},
58 {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i},
56 {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
59 {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
57 {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy"]},
60 {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy", "gradle"], file: /^Jenkinsfile$/},
58 {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
61 {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
59 {name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]},
62 {name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]},
60 {name: "Haskell (Literate)", mime: "text/x-literate-haskell", mode: "haskell-literate", ext: ["lhs"]},
63 {name: "Haskell (Literate)", mime: "text/x-literate-haskell", mode: "haskell-literate", ext: ["lhs"]},
61 {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
64 {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
62 {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
65 {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
63 {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]},
66 {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]},
64 {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]},
67 {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm", "handlebars", "hbs"], alias: ["xhtml"]},
65 {name: "HTTP", mime: "message/http", mode: "http"},
68 {name: "HTTP", mime: "message/http", mode: "http"},
66 {name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]},
69 {name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]},
67 {name: "Jade", mime: "text/x-jade", mode: "jade", ext: ["jade"]},
70 {name: "Pug", mime: "text/x-pug", mode: "pug", ext: ["jade", "pug"], alias: ["jade"]},
68 {name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]},
71 {name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]},
69 {name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]},
72 {name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]},
70 {name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"],
73 {name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"],
@@ -72,7 +75,7 b''
72 {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
75 {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
73 {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]},
76 {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]},
74 {name: "JSX", mime: "text/jsx", mode: "jsx", ext: ["jsx"]},
77 {name: "JSX", mime: "text/jsx", mode: "jsx", ext: ["jsx"]},
75 {name: "Jinja2", mime: "null", mode: "jinja2"},
78 {name: "Jinja2", mime: "text/jinja2", mode: "jinja2", ext: ["j2", "jinja", "jinja2"]},
76 {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
79 {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
77 {name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]},
80 {name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]},
78 {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
81 {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
@@ -81,75 +84,88 b''
81 {name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
84 {name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
82 {name: "mIRC", mime: "text/mirc", mode: "mirc"},
85 {name: "mIRC", mime: "text/mirc", mode: "mirc"},
83 {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
86 {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
84 {name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb"]},
87 {name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb", "wl", "wls"]},
85 {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
88 {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
86 {name: "MUMPS", mime: "text/x-mumps", mode: "mumps"},
89 {name: "MUMPS", mime: "text/x-mumps", mode: "mumps", ext: ["mps"]},
87 {name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
90 {name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
91 {name: "mbox", mime: "application/mbox", mode: "mbox", ext: ["mbox"]},
88 {name: "MySQL", mime: "text/x-mysql", mode: "sql"},
92 {name: "MySQL", mime: "text/x-mysql", mode: "sql"},
89 {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i},
93 {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i},
90 {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
94 {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
91 {name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]},
95 {name: "NTriples", mimes: ["application/n-triples", "application/n-quads", "text/n-triples"],
92 {name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"]},
96 mode: "ntriples", ext: ["nt", "nq"]},
97 {name: "Objective-C", mime: "text/x-objectivec", mode: "clike", ext: ["m"], alias: ["objective-c", "objc"]},
98 {name: "Objective-C++", mime: "text/x-objectivec++", mode: "clike", ext: ["mm"], alias: ["objective-c++", "objc++"]},
93 {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
99 {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
94 {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
100 {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
95 {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
101 {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
96 {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]},
102 {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]},
97 {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]},
103 {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]},
98 {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]},
104 {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]},
99 {name: "PHP", mime: "application/x-httpd-php", mode: "php", ext: ["php", "php3", "php4", "php5", "phtml"]},
105 {name: "PHP", mimes: ["text/x-php", "application/x-httpd-php", "application/x-httpd-php-open"], mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]},
100 {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
106 {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
101 {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
107 {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
102 {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
108 {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
109 {name: "PostgreSQL", mime: "text/x-pgsql", mode: "sql"},
110 {name: "PowerShell", mime: "application/x-powershell", mode: "powershell", ext: ["ps1", "psd1", "psm1"]},
103 {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
111 {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
104 {name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]},
112 {name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]},
113 {name: "Python", mime: "text/x-python", mode: "python", ext: ["BUILD", "bzl", "py", "pyw"], file: /^(BUCK|BUILD)$/},
105 {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
114 {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
106 {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
115 {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
107 {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"], alias: ["rscript"]},
116 {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r", "R"], alias: ["rscript"]},
108 {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]},
117 {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]},
109 {name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"},
118 {name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"},
110 {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]},
119 {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]},
111 {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]},
120 {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]},
112 {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]},
121 {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]},
122 {name: "SAS", mime: "text/x-sas", mode: "sas", ext: ["sas"]},
113 {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]},
123 {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]},
114 {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]},
124 {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]},
115 {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]},
125 {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]},
116 {name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]},
126 {name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]},
117 {name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"], file: /^PKGBUILD$/},
127 {name: "Shell", mimes: ["text/x-sh", "application/x-sh"], mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"], file: /^PKGBUILD$/},
118 {name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]},
128 {name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]},
119 {name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]},
129 {name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]},
120 {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]},
130 {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]},
121 {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]},
131 {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]},
122 {name: "Solr", mime: "text/x-solr", mode: "solr"},
132 {name: "Solr", mime: "text/x-solr", mode: "solr"},
133 {name: "SML", mime: "text/x-sml", mode: "mllike", ext: ["sml", "sig", "fun", "smackspec"]},
123 {name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]},
134 {name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]},
124 {name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]},
135 {name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]},
125 {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]},
136 {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]},
126 {name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
137 {name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
138 {name: "SQLite", mime: "text/x-sqlite", mode: "sql"},
127 {name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]},
139 {name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]},
140 {name: "Stylus", mime: "text/x-styl", mode: "stylus", ext: ["styl"]},
128 {name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]},
141 {name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]},
129 {name: "MariaDB", mime: "text/x-mariadb", mode: "sql"},
130 {name: "sTeX", mime: "text/x-stex", mode: "stex"},
142 {name: "sTeX", mime: "text/x-stex", mode: "stex"},
131 {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]},
143 {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx", "tex"], alias: ["tex"]},
132 {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]},
144 {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v", "sv", "svh"]},
133 {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
145 {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
134 {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]},
146 {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]},
135 {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"},
147 {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"},
136 {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
148 {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
137 {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
149 {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
138 {name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
150 {name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
139 {name: "troff", mime: "troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]},
151 {name: "troff", mime: "text/troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]},
140 {name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]},
152 {name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]},
141 {name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]},
153 {name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]},
142 {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
154 {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
143 {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]},
155 {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]},
156 {name: "TypeScript-JSX", mime: "text/typescript-jsx", mode: "jsx", ext: ["tsx"], alias: ["tsx"]},
144 {name: "Twig", mime: "text/x-twig", mode: "twig"},
157 {name: "Twig", mime: "text/x-twig", mode: "twig"},
158 {name: "Web IDL", mime: "text/x-webidl", mode: "webidl", ext: ["webidl"]},
145 {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]},
159 {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]},
146 {name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]},
160 {name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]},
147 {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]},
161 {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]},
148 {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]},
162 {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]},
149 {name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]},
163 {name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]},
150 {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]},
164 {name: "Vue.js Component", mimes: ["script/x-vue", "text/x-vue"], mode: "vue", ext: ["vue"]},
165 {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd", "svg"], alias: ["rss", "wsdl", "xsd"]},
151 {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]},
166 {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]},
152 {name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]},
167 {name: "Yacas", mime: "text/x-yacas", mode: "yacas", ext: ["ys"]},
168 {name: "YAML", mimes: ["text/x-yaml", "text/yaml"], mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]},
153 {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]},
169 {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]},
154 {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]},
170 {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]},
155 {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]},
171 {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]},
@@ -169,6 +185,8 b''
169 if (info.mimes) for (var j = 0; j < info.mimes.length; j++)
185 if (info.mimes) for (var j = 0; j < info.mimes.length; j++)
170 if (info.mimes[j] == mime) return info;
186 if (info.mimes[j] == mime) return info;
171 }
187 }
188 if (/\+xml$/.test(mime)) return CodeMirror.findModeByMIME("application/xml")
189 if (/\+json$/.test(mime)) return CodeMirror.findModeByMIME("application/json")
172 };
190 };
173
191
174 CodeMirror.findModeByExtension = function(ext) {
192 CodeMirror.findModeByExtension = function(ext) {
@@ -36,7 +36,7 b' MIME_TO_EXT = {'
36 "application/x-ssp": {"exts": ["*.ssp"], "mode": ""},
36 "application/x-ssp": {"exts": ["*.ssp"], "mode": ""},
37 "application/x-troff": {"exts": ["*.[1234567]","*.man"], "mode": ""},
37 "application/x-troff": {"exts": ["*.[1234567]","*.man"], "mode": ""},
38 "application/x-urbiscript": {"exts": ["*.u"], "mode": ""},
38 "application/x-urbiscript": {"exts": ["*.u"], "mode": ""},
39 "application/xml": {"exts": ["*.xml","*.xsl","*.rss","*.xslt","*.xsd","*.wsdl"], "mode": "xml"},
39 "application/xml": {"exts": ["*.xml","*.xsl","*.rss","*.xslt","*.xsd","*.wsdl","*.svg"], "mode": "xml"},
40 "application/xml+evoque": {"exts": ["*.xml"], "mode": ""},
40 "application/xml+evoque": {"exts": ["*.xml"], "mode": ""},
41 "application/xml-dtd": {"exts": ["*.dtd"], "mode": "dtd"},
41 "application/xml-dtd": {"exts": ["*.dtd"], "mode": "dtd"},
42 "application/xquery": {"exts": ["*.xqy","*.xquery","*.xq","*.xql","*.xqm","*.xy"], "mode": "xquery"},
42 "application/xquery": {"exts": ["*.xqy","*.xquery","*.xq","*.xql","*.xqm","*.xy"], "mode": "xquery"},
@@ -48,7 +48,7 b' MIME_TO_EXT = {'
48 "text/coffeescript": {"exts": ["*.coffee"], "mode": ""},
48 "text/coffeescript": {"exts": ["*.coffee"], "mode": ""},
49 "text/css": {"exts": ["*.css"], "mode": "css"},
49 "text/css": {"exts": ["*.css"], "mode": "css"},
50 "text/haxe": {"exts": ["*.hx"], "mode": ""},
50 "text/haxe": {"exts": ["*.hx"], "mode": ""},
51 "text/html": {"exts": ["*.html","*.htm","*.xhtml","*.xslt"], "mode": "htmlmixed"},
51 "text/html": {"exts": ["*.html","*.htm","*.xhtml","*.xslt","*.handlebars","*.hbs"], "mode": "htmlmixed"},
52 "text/html+evoque": {"exts": ["*.html"], "mode": ""},
52 "text/html+evoque": {"exts": ["*.html"], "mode": ""},
53 "text/html+ruby": {"exts": ["*.rhtml"], "mode": ""},
53 "text/html+ruby": {"exts": ["*.rhtml"], "mode": ""},
54 "text/idl": {"exts": ["*.pro"], "mode": ""},
54 "text/idl": {"exts": ["*.pro"], "mode": ""},
@@ -80,7 +80,7 b' MIME_TO_EXT = {'
80 "text/x-c-objdump": {"exts": ["*.c-objdump"], "mode": ""},
80 "text/x-c-objdump": {"exts": ["*.c-objdump"], "mode": ""},
81 "text/x-ceylon": {"exts": ["*.ceylon"], "mode": ""},
81 "text/x-ceylon": {"exts": ["*.ceylon"], "mode": ""},
82 "text/x-chdr": {"exts": ["*.c","*.h","*.idc"], "mode": "clike"},
82 "text/x-chdr": {"exts": ["*.c","*.h","*.idc"], "mode": "clike"},
83 "text/x-clojure": {"exts": ["*.clj"], "mode": "clojure"},
83 "text/x-clojure": {"exts": ["*.clj","*.cljc","*.cljx"], "mode": "clojure"},
84 "text/x-cmake": {"exts": ["*.cmake","CMakeLists.txt","*.cmake.in"], "mode": "cmake"},
84 "text/x-cmake": {"exts": ["*.cmake","CMakeLists.txt","*.cmake.in"], "mode": "cmake"},
85 "text/x-cobol": {"exts": ["*.cob","*.COB","*.cpy","*.CPY"], "mode": "cobol"},
85 "text/x-cobol": {"exts": ["*.cob","*.COB","*.cpy","*.CPY"], "mode": "cobol"},
86 "text/x-coffeescript": {"exts": ["*.coffee"], "mode": "coffeescript"},
86 "text/x-coffeescript": {"exts": ["*.coffee"], "mode": "coffeescript"},
@@ -89,7 +89,7 b' MIME_TO_EXT = {'
89 "text/x-cpp-objdump": {"exts": ["*.cpp-objdump","*.c++-objdump","*.cxx-objdump"], "mode": ""},
89 "text/x-cpp-objdump": {"exts": ["*.cpp-objdump","*.c++-objdump","*.cxx-objdump"], "mode": ""},
90 "text/x-crocsrc": {"exts": ["*.croc"], "mode": ""},
90 "text/x-crocsrc": {"exts": ["*.croc"], "mode": ""},
91 "text/x-csharp": {"exts": ["*.cs"], "mode": "clike"},
91 "text/x-csharp": {"exts": ["*.cs"], "mode": "clike"},
92 "text/x-csrc": {"exts": ["*.c","*.h"], "mode": "clike"},
92 "text/x-csrc": {"exts": ["*.c","*.h","*.ino"], "mode": "clike"},
93 "text/x-cuda": {"exts": ["*.cu","*.cuh"], "mode": ""},
93 "text/x-cuda": {"exts": ["*.cu","*.cuh"], "mode": ""},
94 "text/x-cython": {"exts": ["*.pyx","*.pxd","*.pxi"], "mode": "python"},
94 "text/x-cython": {"exts": ["*.pyx","*.pxd","*.pxi"], "mode": "python"},
95 "text/x-d": {"exts": ["*.d"], "mode": "d"},
95 "text/x-d": {"exts": ["*.d"], "mode": "d"},
@@ -110,7 +110,7 b' MIME_TO_EXT = {'
110 "text/x-factor": {"exts": ["*.factor"], "mode": "factor"},
110 "text/x-factor": {"exts": ["*.factor"], "mode": "factor"},
111 "text/x-fancysrc": {"exts": ["*.fy","*.fancypack"], "mode": ""},
111 "text/x-fancysrc": {"exts": ["*.fy","*.fancypack"], "mode": ""},
112 "text/x-felix": {"exts": ["*.flx","*.flxh"], "mode": ""},
112 "text/x-felix": {"exts": ["*.flx","*.flxh"], "mode": ""},
113 "text/x-fortran": {"exts": ["*.f","*.f90","*.F","*.F90","*.for","*.f77"], "mode": "fortran"},
113 "text/x-fortran": {"exts": ["*.f","*.f90","*.F","*.F90","*.for","*.f77","*.f95"], "mode": "fortran"},
114 "text/x-fsharp": {"exts": ["*.fs","*.fsi"], "mode": "mllike"},
114 "text/x-fsharp": {"exts": ["*.fs","*.fsi"], "mode": "mllike"},
115 "text/x-gas": {"exts": ["*.s","*.S"], "mode": "gas"},
115 "text/x-gas": {"exts": ["*.s","*.S"], "mode": "gas"},
116 "text/x-gfm": {"exts": ["*.md","*.MD"], "mode": "gfm"},
116 "text/x-gfm": {"exts": ["*.md","*.MD"], "mode": "gfm"},
@@ -123,7 +123,7 b' MIME_TO_EXT = {'
123 "text/x-gosrc": {"exts": ["*.go"], "mode": ""},
123 "text/x-gosrc": {"exts": ["*.go"], "mode": ""},
124 "text/x-gosu": {"exts": ["*.gs","*.gsx","*.gsp","*.vark"], "mode": ""},
124 "text/x-gosu": {"exts": ["*.gs","*.gsx","*.gsp","*.vark"], "mode": ""},
125 "text/x-gosu-template": {"exts": ["*.gst"], "mode": ""},
125 "text/x-gosu-template": {"exts": ["*.gst"], "mode": ""},
126 "text/x-groovy": {"exts": ["*.groovy"], "mode": "groovy"},
126 "text/x-groovy": {"exts": ["*.groovy","*.gradle"], "mode": "groovy"},
127 "text/x-haml": {"exts": ["*.haml"], "mode": "haml"},
127 "text/x-haml": {"exts": ["*.haml"], "mode": "haml"},
128 "text/x-haskell": {"exts": ["*.hs"], "mode": "haskell"},
128 "text/x-haskell": {"exts": ["*.hs"], "mode": "haskell"},
129 "text/x-haxe": {"exts": ["*.hx"], "mode": "haxe"},
129 "text/x-haxe": {"exts": ["*.hx"], "mode": "haxe"},
@@ -139,7 +139,7 b' MIME_TO_EXT = {'
139 "text/x-koka": {"exts": ["*.kk","*.kki"], "mode": ""},
139 "text/x-koka": {"exts": ["*.kk","*.kki"], "mode": ""},
140 "text/x-kotlin": {"exts": ["*.kt"], "mode": "clike"},
140 "text/x-kotlin": {"exts": ["*.kt"], "mode": "clike"},
141 "text/x-lasso": {"exts": ["*.lasso","*.lasso[89]"], "mode": ""},
141 "text/x-lasso": {"exts": ["*.lasso","*.lasso[89]"], "mode": ""},
142 "text/x-latex": {"exts": ["*.ltx","*.text"], "mode": "stex"},
142 "text/x-latex": {"exts": ["*.ltx","*.text","*.tex"], "mode": "stex"},
143 "text/x-less": {"exts": ["*.less"], "mode": "css"},
143 "text/x-less": {"exts": ["*.less"], "mode": "css"},
144 "text/x-literate-haskell": {"exts": ["*.lhs"], "mode": "haskell-literate"},
144 "text/x-literate-haskell": {"exts": ["*.lhs"], "mode": "haskell-literate"},
145 "text/x-livescript": {"exts": ["*.ls"], "mode": "livescript"},
145 "text/x-livescript": {"exts": ["*.ls"], "mode": "livescript"},
@@ -173,13 +173,13 b' MIME_TO_EXT = {'
173 "text/x-openedge": {"exts": ["*.p","*.cls"], "mode": ""},
173 "text/x-openedge": {"exts": ["*.p","*.cls"], "mode": ""},
174 "text/x-pascal": {"exts": ["*.pas","*.p"], "mode": "pascal"},
174 "text/x-pascal": {"exts": ["*.pas","*.p"], "mode": "pascal"},
175 "text/x-perl": {"exts": ["*.pl","*.pm"], "mode": "perl"},
175 "text/x-perl": {"exts": ["*.pl","*.pm"], "mode": "perl"},
176 "text/x-php": {"exts": ["*.php","*.php[345]","*.inc"], "mode": "php"},
176 "text/x-php": {"exts": ["*.php","*.php[345]","*.inc","*.php3","*.php4","*.php5","*.php7","*.phtml"], "mode": "php"},
177 "text/x-pig": {"exts": ["*.pig"], "mode": "pig"},
177 "text/x-pig": {"exts": ["*.pig"], "mode": "pig"},
178 "text/x-povray": {"exts": ["*.pov","*.inc"], "mode": ""},
178 "text/x-povray": {"exts": ["*.pov","*.inc"], "mode": ""},
179 "text/x-powershell": {"exts": ["*.ps1"], "mode": ""},
179 "text/x-powershell": {"exts": ["*.ps1"], "mode": ""},
180 "text/x-prolog": {"exts": ["*.prolog","*.pro","*.pl"], "mode": ""},
180 "text/x-prolog": {"exts": ["*.prolog","*.pro","*.pl"], "mode": ""},
181 "text/x-properties": {"exts": ["*.properties","*.ini","*.in"], "mode": "properties"},
181 "text/x-properties": {"exts": ["*.properties","*.ini","*.in"], "mode": "properties"},
182 "text/x-python": {"exts": ["*.py","*.pyw","*.sc","SConstruct","SConscript","*.tac","*.sage"], "mode": "python"},
182 "text/x-python": {"exts": ["*.py","*.pyw","*.sc","SConstruct","SConscript","*.tac","*.sage","*.BUILD","*.bzl"], "mode": "python"},
183 "text/x-python-traceback": {"exts": ["*.pytb"], "mode": ""},
183 "text/x-python-traceback": {"exts": ["*.pytb"], "mode": ""},
184 "text/x-python3-traceback": {"exts": ["*.py3tb"], "mode": ""},
184 "text/x-python3-traceback": {"exts": ["*.py3tb"], "mode": ""},
185 "text/x-r-doc": {"exts": ["*.Rd"], "mode": ""},
185 "text/x-r-doc": {"exts": ["*.Rd"], "mode": ""},
@@ -187,7 +187,7 b' MIME_TO_EXT = {'
187 "text/x-rebol": {"exts": ["*.r","*.r3"], "mode": ""},
187 "text/x-rebol": {"exts": ["*.r","*.r3"], "mode": ""},
188 "text/x-robotframework": {"exts": ["*.txt","*.robot"], "mode": ""},
188 "text/x-robotframework": {"exts": ["*.txt","*.robot"], "mode": ""},
189 "text/x-rpm-spec": {"exts": ["*.spec"], "mode": "rpm"},
189 "text/x-rpm-spec": {"exts": ["*.spec"], "mode": "rpm"},
190 "text/x-rsrc": {"exts": ["*.r"], "mode": "r"},
190 "text/x-rsrc": {"exts": ["*.r","*.R"], "mode": "r"},
191 "text/x-rst": {"exts": ["*.rst","*.rest"], "mode": "rst"},
191 "text/x-rst": {"exts": ["*.rst","*.rest"], "mode": "rst"},
192 "text/x-ruby": {"exts": ["*.rb","*.rbw","Rakefile","*.rake","*.gemspec","*.rbx","*.duby"], "mode": "ruby"},
192 "text/x-ruby": {"exts": ["*.rb","*.rbw","Rakefile","*.rake","*.gemspec","*.rbx","*.duby"], "mode": "ruby"},
193 "text/x-rustsrc": {"exts": ["*.rs","*.rc"], "mode": "rust"},
193 "text/x-rustsrc": {"exts": ["*.rs","*.rc"], "mode": "rust"},
@@ -224,7 +224,7 b' MIME_TO_EXT = {'
224 "text/x-yaml": {"exts": ["*.yaml","*.yml"], "mode": "yaml"},
224 "text/x-yaml": {"exts": ["*.yaml","*.yml"], "mode": "yaml"},
225 "text/x-z80": {"exts": ["*.z80"], "mode": "z80"},
225 "text/x-z80": {"exts": ["*.z80"], "mode": "z80"},
226 "text/xml": {"exts": ["*.xml","*.xsl","*.rss","*.xslt","*.xsd","*.wsdl"], "mode": ""},
226 "text/xml": {"exts": ["*.xml","*.xsl","*.rss","*.xslt","*.xsd","*.wsdl"], "mode": ""},
227 "text/xquery": {"exts": ["*.xqy","*.xquery","*.xq","*.xql","*.xqm"], "mode": ""}
227 "text/xquery": {"exts": ["*.xqy","*.xquery","*.xq","*.xql","*.xqm"], "mode": ""},
228 };
228 };
229
229
230 /* Special case for overriding mode by file extensions
230 /* Special case for overriding mode by file extensions
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 //mIRC mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara
4 //mIRC mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara
5
5
@@ -130,7 +130,7 b' CodeMirror.defineMode("mirc", function()'
130 }
130 }
131 }
131 }
132 else if (ch == "%") {
132 else if (ch == "%") {
133 stream.eatWhile(/[^,^\s^\(^\)]/);
133 stream.eatWhile(/[^,\s()]/);
134 state.beforeParams = true;
134 state.beforeParams = true;
135 return "string";
135 return "string";
136 }
136 }
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -13,31 +13,26 b''
13
13
14 CodeMirror.defineMode('mllike', function(_config, parserConfig) {
14 CodeMirror.defineMode('mllike', function(_config, parserConfig) {
15 var words = {
15 var words = {
16 'let': 'keyword',
16 'as': 'keyword',
17 'rec': 'keyword',
18 'in': 'keyword',
19 'of': 'keyword',
20 'and': 'keyword',
21 'if': 'keyword',
22 'then': 'keyword',
23 'else': 'keyword',
24 'for': 'keyword',
25 'to': 'keyword',
26 'while': 'keyword',
27 'do': 'keyword',
17 'do': 'keyword',
28 'done': 'keyword',
18 'else': 'keyword',
19 'end': 'keyword',
20 'exception': 'keyword',
29 'fun': 'keyword',
21 'fun': 'keyword',
30 'function': 'keyword',
22 'functor': 'keyword',
31 'val': 'keyword',
23 'if': 'keyword',
24 'in': 'keyword',
25 'include': 'keyword',
26 'let': 'keyword',
27 'of': 'keyword',
28 'open': 'keyword',
29 'rec': 'keyword',
30 'struct': 'keyword',
31 'then': 'keyword',
32 'type': 'keyword',
32 'type': 'keyword',
33 'mutable': 'keyword',
33 'val': 'keyword',
34 'match': 'keyword',
34 'while': 'keyword',
35 'with': 'keyword',
35 'with': 'keyword'
36 'try': 'keyword',
37 'open': 'builtin',
38 'ignore': 'builtin',
39 'begin': 'keyword',
40 'end': 'keyword'
41 };
36 };
42
37
43 var extraWords = parserConfig.extraWords || {};
38 var extraWords = parserConfig.extraWords || {};
@@ -46,6 +41,9 b" CodeMirror.defineMode('mllike', function"
46 words[prop] = parserConfig.extraWords[prop];
41 words[prop] = parserConfig.extraWords[prop];
47 }
42 }
48 }
43 }
44 var hintWords = [];
45 for (var k in words) { hintWords.push(k); }
46 CodeMirror.registerHelper("hintWords", "mllike", hintWords);
49
47
50 function tokenBase(stream, state) {
48 function tokenBase(stream, state) {
51 var ch = stream.next();
49 var ch = stream.next();
@@ -54,6 +52,13 b" CodeMirror.defineMode('mllike', function"
54 state.tokenize = tokenString;
52 state.tokenize = tokenString;
55 return state.tokenize(stream, state);
53 return state.tokenize(stream, state);
56 }
54 }
55 if (ch === '{') {
56 if (stream.eat('|')) {
57 state.longString = true;
58 state.tokenize = tokenLongString;
59 return state.tokenize(stream, state);
60 }
61 }
57 if (ch === '(') {
62 if (ch === '(') {
58 if (stream.eat('*')) {
63 if (stream.eat('*')) {
59 state.commentLevel++;
64 state.commentLevel++;
@@ -61,7 +66,7 b" CodeMirror.defineMode('mllike', function"
61 return state.tokenize(stream, state);
66 return state.tokenize(stream, state);
62 }
67 }
63 }
68 }
64 if (ch === '~') {
69 if (ch === '~' || ch === '?') {
65 stream.eatWhile(/\w/);
70 stream.eatWhile(/\w/);
66 return 'variable-2';
71 return 'variable-2';
67 }
72 }
@@ -74,19 +79,33 b" CodeMirror.defineMode('mllike', function"
74 return 'comment';
79 return 'comment';
75 }
80 }
76 if (/\d/.test(ch)) {
81 if (/\d/.test(ch)) {
77 stream.eatWhile(/[\d]/);
82 if (ch === '0' && stream.eat(/[bB]/)) {
83 stream.eatWhile(/[01]/);
84 } if (ch === '0' && stream.eat(/[xX]/)) {
85 stream.eatWhile(/[0-9a-fA-F]/)
86 } if (ch === '0' && stream.eat(/[oO]/)) {
87 stream.eatWhile(/[0-7]/);
88 } else {
89 stream.eatWhile(/[\d_]/);
78 if (stream.eat('.')) {
90 if (stream.eat('.')) {
79 stream.eatWhile(/[\d]/);
91 stream.eatWhile(/[\d]/);
80 }
92 }
93 if (stream.eat(/[eE]/)) {
94 stream.eatWhile(/[\d\-+]/);
95 }
96 }
81 return 'number';
97 return 'number';
82 }
98 }
83 if ( /[+\-*&%=<>!?|]/.test(ch)) {
99 if ( /[+\-*&%=<>!?|@\.~:]/.test(ch)) {
84 return 'operator';
100 return 'operator';
85 }
101 }
86 stream.eatWhile(/\w/);
102 if (/[\w\xa1-\uffff]/.test(ch)) {
103 stream.eatWhile(/[\w\xa1-\uffff]/);
87 var cur = stream.current();
104 var cur = stream.current();
88 return words.hasOwnProperty(cur) ? words[cur] : 'variable';
105 return words.hasOwnProperty(cur) ? words[cur] : 'variable';
89 }
106 }
107 return null
108 }
90
109
91 function tokenString(stream, state) {
110 function tokenString(stream, state) {
92 var next, end = false, escaped = false;
111 var next, end = false, escaped = false;
@@ -116,8 +135,20 b" CodeMirror.defineMode('mllike', function"
116 return 'comment';
135 return 'comment';
117 }
136 }
118
137
138 function tokenLongString(stream, state) {
139 var prev, next;
140 while (state.longString && (next = stream.next()) != null) {
141 if (prev === '|' && next === '}') state.longString = false;
142 prev = next;
143 }
144 if (!state.longString) {
145 state.tokenize = tokenBase;
146 }
147 return 'string';
148 }
149
119 return {
150 return {
120 startState: function() {return {tokenize: tokenBase, commentLevel: 0};},
151 startState: function() {return {tokenize: tokenBase, commentLevel: 0, longString: false};},
121 token: function(stream, state) {
152 token: function(stream, state) {
122 if (stream.eatSpace()) return null;
153 if (stream.eatSpace()) return null;
123 return state.tokenize(stream, state);
154 return state.tokenize(stream, state);
@@ -132,14 +163,64 b" CodeMirror.defineMode('mllike', function"
132 CodeMirror.defineMIME('text/x-ocaml', {
163 CodeMirror.defineMIME('text/x-ocaml', {
133 name: 'mllike',
164 name: 'mllike',
134 extraWords: {
165 extraWords: {
135 'succ': 'keyword',
166 'and': 'keyword',
167 'assert': 'keyword',
168 'begin': 'keyword',
169 'class': 'keyword',
170 'constraint': 'keyword',
171 'done': 'keyword',
172 'downto': 'keyword',
173 'external': 'keyword',
174 'function': 'keyword',
175 'initializer': 'keyword',
176 'lazy': 'keyword',
177 'match': 'keyword',
178 'method': 'keyword',
179 'module': 'keyword',
180 'mutable': 'keyword',
181 'new': 'keyword',
182 'nonrec': 'keyword',
183 'object': 'keyword',
184 'private': 'keyword',
185 'sig': 'keyword',
186 'to': 'keyword',
187 'try': 'keyword',
188 'value': 'keyword',
189 'virtual': 'keyword',
190 'when': 'keyword',
191
192 // builtins
193 'raise': 'builtin',
194 'failwith': 'builtin',
195 'true': 'builtin',
196 'false': 'builtin',
197
198 // Pervasives builtins
199 'asr': 'builtin',
200 'land': 'builtin',
201 'lor': 'builtin',
202 'lsl': 'builtin',
203 'lsr': 'builtin',
204 'lxor': 'builtin',
205 'mod': 'builtin',
206 'or': 'builtin',
207
208 // More Pervasives
209 'raise_notrace': 'builtin',
136 'trace': 'builtin',
210 'trace': 'builtin',
137 'exit': 'builtin',
211 'exit': 'builtin',
138 'print_string': 'builtin',
212 'print_string': 'builtin',
139 'print_endline': 'builtin',
213 'print_endline': 'builtin',
140 'true': 'atom',
214
141 'false': 'atom',
215 'int': 'type',
142 'raise': 'keyword'
216 'float': 'type',
217 'bool': 'type',
218 'char': 'type',
219 'string': 'type',
220 'unit': 'type',
221
222 // Modules
223 'List': 'builtin'
143 }
224 }
144 });
225 });
145
226
@@ -147,18 +228,21 b" CodeMirror.defineMIME('text/x-fsharp', {"
147 name: 'mllike',
228 name: 'mllike',
148 extraWords: {
229 extraWords: {
149 'abstract': 'keyword',
230 'abstract': 'keyword',
150 'as': 'keyword',
151 'assert': 'keyword',
231 'assert': 'keyword',
152 'base': 'keyword',
232 'base': 'keyword',
233 'begin': 'keyword',
153 'class': 'keyword',
234 'class': 'keyword',
154 'default': 'keyword',
235 'default': 'keyword',
155 'delegate': 'keyword',
236 'delegate': 'keyword',
237 'do!': 'keyword',
238 'done': 'keyword',
156 'downcast': 'keyword',
239 'downcast': 'keyword',
157 'downto': 'keyword',
240 'downto': 'keyword',
158 'elif': 'keyword',
241 'elif': 'keyword',
159 'exception': 'keyword',
160 'extern': 'keyword',
242 'extern': 'keyword',
161 'finally': 'keyword',
243 'finally': 'keyword',
244 'for': 'keyword',
245 'function': 'keyword',
162 'global': 'keyword',
246 'global': 'keyword',
163 'inherit': 'keyword',
247 'inherit': 'keyword',
164 'inline': 'keyword',
248 'inline': 'keyword',
@@ -166,38 +250,108 b" CodeMirror.defineMIME('text/x-fsharp', {"
166 'internal': 'keyword',
250 'internal': 'keyword',
167 'lazy': 'keyword',
251 'lazy': 'keyword',
168 'let!': 'keyword',
252 'let!': 'keyword',
253 'match': 'keyword',
169 'member' : 'keyword',
254 'member': 'keyword',
170 'module': 'keyword',
255 'module': 'keyword',
256 'mutable': 'keyword',
171 'namespace': 'keyword',
257 'namespace': 'keyword',
172 'new': 'keyword',
258 'new': 'keyword',
173 'null': 'keyword',
259 'null': 'keyword',
174 'override': 'keyword',
260 'override': 'keyword',
175 'private': 'keyword',
261 'private': 'keyword',
176 'public': 'keyword',
262 'public': 'keyword',
263 'return!': 'keyword',
177 'return': 'keyword',
264 'return': 'keyword',
178 'return!': 'keyword',
179 'select': 'keyword',
265 'select': 'keyword',
180 'static': 'keyword',
266 'static': 'keyword',
181 'struct': 'keyword',
267 'to': 'keyword',
268 'try': 'keyword',
182 'upcast': 'keyword',
269 'upcast': 'keyword',
183 'use': 'keyword',
184 'use!': 'keyword',
270 'use!': 'keyword',
185 'val': 'keyword',
271 'use': 'keyword',
272 'void': 'keyword',
186 'when': 'keyword',
273 'when': 'keyword',
274 'yield!': 'keyword',
187 'yield': 'keyword',
275 'yield': 'keyword',
188 'yield!': 'keyword',
189
276
277 // Reserved words
278 'atomic': 'keyword',
279 'break': 'keyword',
280 'checked': 'keyword',
281 'component': 'keyword',
282 'const': 'keyword',
283 'constraint': 'keyword',
284 'constructor': 'keyword',
285 'continue': 'keyword',
286 'eager': 'keyword',
287 'event': 'keyword',
288 'external': 'keyword',
289 'fixed': 'keyword',
290 'method': 'keyword',
291 'mixin': 'keyword',
292 'object': 'keyword',
293 'parallel': 'keyword',
294 'process': 'keyword',
295 'protected': 'keyword',
296 'pure': 'keyword',
297 'sealed': 'keyword',
298 'tailcall': 'keyword',
299 'trait': 'keyword',
300 'virtual': 'keyword',
301 'volatile': 'keyword',
302
303 // builtins
190 'List': 'builtin',
304 'List': 'builtin',
191 'Seq': 'builtin',
305 'Seq': 'builtin',
192 'Map': 'builtin',
306 'Map': 'builtin',
193 'Set': 'builtin',
307 'Set': 'builtin',
308 'Option': 'builtin',
194 'int': 'builtin',
309 'int': 'builtin',
195 'string': 'builtin',
310 'string': 'builtin',
196 'raise': 'builtin',
197 'failwith': 'builtin',
198 'not': 'builtin',
311 'not': 'builtin',
199 'true': 'builtin',
312 'true': 'builtin',
200 'false': 'builtin'
313 'false': 'builtin',
314
315 'raise': 'builtin',
316 'failwith': 'builtin'
317 },
318 slashComments: true
319 });
320
321
322 CodeMirror.defineMIME('text/x-sml', {
323 name: 'mllike',
324 extraWords: {
325 'abstype': 'keyword',
326 'and': 'keyword',
327 'andalso': 'keyword',
328 'case': 'keyword',
329 'datatype': 'keyword',
330 'fn': 'keyword',
331 'handle': 'keyword',
332 'infix': 'keyword',
333 'infixr': 'keyword',
334 'local': 'keyword',
335 'nonfix': 'keyword',
336 'op': 'keyword',
337 'orelse': 'keyword',
338 'raise': 'keyword',
339 'withtype': 'keyword',
340 'eqtype': 'keyword',
341 'sharing': 'keyword',
342 'sig': 'keyword',
343 'signature': 'keyword',
344 'structure': 'keyword',
345 'where': 'keyword',
346 'true': 'keyword',
347 'false': 'keyword',
348
349 // types
350 'int': 'builtin',
351 'real': 'builtin',
352 'string': 'builtin',
353 'char': 'builtin',
354 'bool': 'builtin'
201 },
355 },
202 slashComments: true
356 slashComments: true
203 });
357 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Modelica support for CodeMirror, copyright (c) by Lennart Ochel
4 // Modelica support for CodeMirror, copyright (c) by Lennart Ochel
5
5
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // mode(s) for the sequence chart dsl's mscgen, xù and msgenny
4 // mode(s) for the sequence chart dsl's mscgen, xù and msgenny
5 // For more information on mscgen, see the site of the original author:
5 // For more information on mscgen, see the site of the original author:
@@ -23,6 +23,7 b''
23 mscgen: {
23 mscgen: {
24 "keywords" : ["msc"],
24 "keywords" : ["msc"],
25 "options" : ["hscale", "width", "arcgradient", "wordwraparcs"],
25 "options" : ["hscale", "width", "arcgradient", "wordwraparcs"],
26 "constants" : ["true", "false", "on", "off"],
26 "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"],
27 "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"],
27 "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists
28 "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists
28 "arcsWords" : ["note", "abox", "rbox", "box"],
29 "arcsWords" : ["note", "abox", "rbox", "box"],
@@ -31,9 +32,10 b''
31 "operators" : ["="]
32 "operators" : ["="]
32 },
33 },
33 xu: {
34 xu: {
34 "keywords" : ["msc"],
35 "keywords" : ["msc", "xu"],
35 "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"],
36 "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "wordwrapentities", "watermark"],
36 "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"],
37 "constants" : ["true", "false", "on", "off", "auto"],
38 "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip", "title", "deactivate", "activate", "activation"],
37 "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists
39 "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists
38 "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"],
40 "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"],
39 "arcsOthers" : ["\\|\\|\\|", "\\.\\.\\.", "---", "--", "<->", "==", "<<=>>", "<=>", "\\.\\.", "<<>>", "::", "<:>", "->", "=>>", "=>", ">>", ":>", "<-", "<<=", "<=", "<<", "<:", "x-", "-x"],
41 "arcsOthers" : ["\\|\\|\\|", "\\.\\.\\.", "---", "--", "<->", "==", "<<=>>", "<=>", "\\.\\.", "<<>>", "::", "<:>", "->", "=>>", "=>", ">>", ":>", "<-", "<<=", "<=", "<<", "<:", "x-", "-x"],
@@ -42,7 +44,8 b''
42 },
44 },
43 msgenny: {
45 msgenny: {
44 "keywords" : null,
46 "keywords" : null,
45 "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"],
47 "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "wordwrapentities", "watermark"],
48 "constants" : ["true", "false", "on", "off", "auto"],
46 "attributes" : null,
49 "attributes" : null,
47 "brackets" : ["\\{", "\\}"],
50 "brackets" : ["\\{", "\\}"],
48 "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"],
51 "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"],
@@ -146,6 +149,9 b''
146 if (!!pConfig.operators && pStream.match(wordRegexp(pConfig.operators), true, true))
149 if (!!pConfig.operators && pStream.match(wordRegexp(pConfig.operators), true, true))
147 return "operator";
150 return "operator";
148
151
152 if (!!pConfig.constants && pStream.match(wordRegexp(pConfig.constants), true, true))
153 return "variable";
154
149 /* attribute lists */
155 /* attribute lists */
150 if (!pConfig.inAttributeList && !!pConfig.attributes && pStream.match(/\[/, true, true)) {
156 if (!pConfig.inAttributeList && !!pConfig.attributes && pStream.match(/\[/, true, true)) {
151 pConfig.inAttributeList = true;
157 pConfig.inAttributeList = true;
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function() {
4 (function() {
5 var mode = CodeMirror.getMode({indentUnit: 2}, "mscgen");
5 var mode = CodeMirror.getMode({indentUnit: 2}, "mscgen");
@@ -26,9 +26,18 b''
26
26
27 MT("xù/ msgenny keywords classify as 'base'",
27 MT("xù/ msgenny keywords classify as 'base'",
28 "[base watermark]",
28 "[base watermark]",
29 "[base wordwrapentities]",
29 "[base alt loop opt ref else break par seq assert]"
30 "[base alt loop opt ref else break par seq assert]"
30 );
31 );
31
32
33 MT("xù/ msgenny constants classify as 'base'",
34 "[base auto]"
35 );
36
37 MT("mscgen constants classify as 'variable'",
38 "[variable true]", "[variable false]", "[variable on]", "[variable off]"
39 );
40
32 MT("mscgen options classify as keyword",
41 MT("mscgen options classify as keyword",
33 "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
42 "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
34 );
43 );
@@ -63,7 +72,7 b''
63 MT("a typical program",
72 MT("a typical program",
64 "[comment # typical mscgen program]",
73 "[comment # typical mscgen program]",
65 "[keyword msc][base ][bracket {]",
74 "[keyword msc][base ][bracket {]",
66 "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][keyword arcgradient][operator =][base 30;]",
75 "[keyword wordwraparcs][operator =][variable true][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]",
67 "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]",
76 "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]",
68 "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]",
77 "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]",
69 "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]",
78 "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]",
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function() {
4 (function() {
5 var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-msgenny");
5 var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-msgenny");
@@ -20,9 +20,15 b''
20
20
21 MT("xù/ msgenny keywords classify as 'keyword'",
21 MT("xù/ msgenny keywords classify as 'keyword'",
22 "[keyword watermark]",
22 "[keyword watermark]",
23 "[keyword wordwrapentities]",
23 "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]"
24 "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]"
24 );
25 );
25
26
27 MT("xù/ msgenny constants classify as 'variable'",
28 "[variable auto]",
29 "[variable true]", "[variable false]", "[variable on]", "[variable off]"
30 );
31
26 MT("mscgen options classify as keyword",
32 MT("mscgen options classify as keyword",
27 "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
33 "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
28 );
34 );
@@ -56,7 +62,7 b''
56
62
57 MT("a typical program",
63 MT("a typical program",
58 "[comment # typical msgenny program]",
64 "[comment # typical msgenny program]",
59 "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]",
65 "[keyword wordwraparcs][operator =][variable true][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]",
60 "[base a : ][string \"Entity A\"][base ,]",
66 "[base a : ][string \"Entity A\"][base ,]",
61 "[base b : Entity B,]",
67 "[base b : Entity B,]",
62 "[base c : Entity C;]",
68 "[base c : Entity C;]",
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function() {
4 (function() {
5 var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-xu");
5 var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-xu");
@@ -11,6 +11,12 b''
11 "[bracket }]"
11 "[bracket }]"
12 );
12 );
13
13
14 MT("empty chart",
15 "[keyword xu][bracket {]",
16 "[base ]",
17 "[bracket }]"
18 );
19
14 MT("comments",
20 MT("comments",
15 "[comment // a single line comment]",
21 "[comment // a single line comment]",
16 "[comment # another single line comment /* and */ ignored here]",
22 "[comment # another single line comment /* and */ ignored here]",
@@ -29,6 +35,11 b''
29 "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]"
35 "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]"
30 );
36 );
31
37
38 MT("xù/ msgenny constants classify as 'variable'",
39 "[variable auto]",
40 "[variable true]", "[variable false]", "[variable on]", "[variable off]"
41 );
42
32 MT("mscgen options classify as keyword",
43 MT("mscgen options classify as keyword",
33 "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
44 "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
34 );
45 );
@@ -49,7 +60,8 b''
49 "[attribute id]","[attribute url]","[attribute idurl]",
60 "[attribute id]","[attribute url]","[attribute idurl]",
50 "[attribute linecolor]","[attribute linecolour]","[attribute textcolor]","[attribute textcolour]","[attribute textbgcolor]","[attribute textbgcolour]",
61 "[attribute linecolor]","[attribute linecolour]","[attribute textcolor]","[attribute textcolour]","[attribute textbgcolor]","[attribute textbgcolour]",
51 "[attribute arclinecolor]","[attribute arclinecolour]","[attribute arctextcolor]","[attribute arctextcolour]","[attribute arctextbgcolor]","[attribute arctextbgcolour]",
62 "[attribute arclinecolor]","[attribute arclinecolour]","[attribute arctextcolor]","[attribute arctextcolour]","[attribute arctextbgcolor]","[attribute arctextbgcolour]",
52 "[attribute arcskip][bracket ]]]"
63 "[attribute arcskip]","[attribute title]",
64 "[attribute activate]","[attribute deactivate]","[attribute activation][bracket ]]]"
53 );
65 );
54
66
55 MT("outside an attribute list, attributes classify as base",
67 MT("outside an attribute list, attributes classify as base",
@@ -57,18 +69,18 b''
57 "[base id]","[base url]","[base idurl]",
69 "[base id]","[base url]","[base idurl]",
58 "[base linecolor]","[base linecolour]","[base textcolor]","[base textcolour]","[base textbgcolor]","[base textbgcolour]",
70 "[base linecolor]","[base linecolour]","[base textcolor]","[base textcolour]","[base textbgcolor]","[base textbgcolour]",
59 "[base arclinecolor]","[base arclinecolour]","[base arctextcolor]","[base arctextcolour]","[base arctextbgcolor]","[base arctextbgcolour]",
71 "[base arclinecolor]","[base arclinecolour]","[base arctextcolor]","[base arctextcolour]","[base arctextbgcolor]","[base arctextbgcolour]",
60 "[base arcskip]"
72 "[base arcskip]", "[base title]"
61 );
73 );
62
74
63 MT("a typical program",
75 MT("a typical program",
64 "[comment # typical mscgen program]",
76 "[comment # typical xu program]",
65 "[keyword msc][base ][bracket {]",
77 "[keyword xu][base ][bracket {]",
66 "[keyword wordwraparcs][operator =][string \"true\"][keyword hscale][operator =][string \"0.8\"][keyword arcgradient][operator =][base 30;]",
78 "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30, ][keyword width][operator =][variable auto][base ;]",
67 "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]",
79 "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]",
68 "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]",
80 "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]",
69 "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]",
81 "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]",
70 "[base a ][keyword =>>][base b][bracket [[][attribute label][operator =][string \"Hello entity B\"][bracket ]]][base ;]",
82 "[base a ][keyword =>>][base b][bracket [[][attribute label][operator =][string \"Hello entity B\"][bracket ]]][base ;]",
71 "[base a ][keyword <<][base b][bracket [[][attribute label][operator =][string \"Here's an answer dude!\"][bracket ]]][base ;]",
83 "[base a ][keyword <<][base b][bracket [[][attribute label][operator =][string \"Here's an answer dude!\"][base , ][attribute title][operator =][string \"This is a title for this message\"][bracket ]]][base ;]",
72 "[base c ][keyword :>][base *][bracket [[][attribute label][operator =][string \"What about me?\"][base , ][attribute textcolor][operator =][base red][bracket ]]][base ;]",
84 "[base c ][keyword :>][base *][bracket [[][attribute label][operator =][string \"What about me?\"][base , ][attribute textcolor][operator =][base red][bracket ]]][base ;]",
73 "[bracket }]"
85 "[bracket }]"
74 );
86 );
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /*
4 /*
5 This MUMPS Language script was constructed using vbscript.js as a template.
5 This MUMPS Language script was constructed using vbscript.js as a template.
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Author: Jan T. Sott (http://github.com/idleberg)
4 // Author: Jan T. Sott (http://github.com/idleberg)
5
5
@@ -24,20 +24,20 b' CodeMirror.defineSimpleMode("nsis",{'
24 { regex: /`(?:[^\\`]|\\.)*`?/, token: "string" },
24 { regex: /`(?:[^\\`]|\\.)*`?/, token: "string" },
25
25
26 // Compile Time Commands
26 // Compile Time Commands
27 {regex: /(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|finalize|getdllversion|system|tempfile|warning|verbose|define|undef|insertmacro|makensis|searchparse|searchreplace))\b/, token: "keyword"},
27 {regex: /^\s*(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|pragma|finalize|getdllversion|gettlbversion|system|tempfile|warning|verbose|define|undef|insertmacro|macro|macroend|makensis|searchparse|searchreplace))\b/, token: "keyword"},
28
28
29 // Conditional Compilation
29 // Conditional Compilation
30 {regex: /(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/, token: "keyword", indent: true},
30 {regex: /^\s*(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/, token: "keyword", indent: true},
31 {regex: /(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true},
31 {regex: /^\s*(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true},
32
32
33 // Runtime Commands
33 // Runtime Commands
34 {regex: /\b(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|IntCmp|IntCmpU|IntFmt|IntOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetPluginUnload|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"},
34 {regex: /^\s*(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecShellWait|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|Int64Cmp|Int64CmpU|Int64Fmt|IntCmp|IntCmpU|IntFmt|IntOp|IntPtrCmp|IntPtrCmpU|IntPtrOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|PEDllCharacteristics|PESubsysVer|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegMultiStr|WriteRegNone|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"},
35 {regex: /\b(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true},
35 {regex: /^\s*(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true},
36 {regex: /\b(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true},
36 {regex: /^\s*(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true},
37
37
38 // Command Options
38 // Command Options
39 {regex: /\b(?:ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HIDDEN|HKCC|HKCR|HKCU|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM|HKPD|HKU|IDABORT|IDCANCEL|IDD_DIR|IDD_INST|IDD_INSTFILES|IDD_LICENSE|IDD_SELCOM|IDD_UNINST|IDD_VERIFY|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|MB_YESNOCANCEL|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SW_HIDE|SW_SHOWDEFAULT|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_SHOWNORMAL|SYSTEM|TEMPORARY)\b/, token: "atom"},
39 {regex: /\b(?:ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HIDDEN|HKCC|HKCR(32|64)?|HKCU(32|64)?|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM(32|64)?|HKPD|HKU|IDABORT|IDCANCEL|IDD_DIR|IDD_INST|IDD_INSTFILES|IDD_LICENSE|IDD_SELCOM|IDD_UNINST|IDD_VERIFY|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|MB_YESNOCANCEL|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SW_HIDE|SW_SHOWDEFAULT|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_SHOWNORMAL|SYSTEM|TEMPORARY)\b/, token: "atom"},
40 {regex: /\b(?:admin|all|auto|both|bottom|bzip2|components|current|custom|directory|force|hide|highest|ifdiff|ifnewer|instfiles|lastused|leave|left|license|listonly|lzma|nevershow|none|normal|notset|right|show|silent|silentlog|textonly|top|try|un\.components|un\.custom|un\.directory|un\.instfiles|un\.license|uninstConfirm|user|Win10|Win7|Win8|WinVista|zlib)\b/, token: "builtin"},
40 {regex: /\b(?:admin|all|auto|both|bottom|bzip2|components|current|custom|directory|false|force|hide|highest|ifdiff|ifnewer|instfiles|lastused|leave|left|license|listonly|lzma|nevershow|none|normal|notset|off|on|right|show|silent|silentlog|textonly|top|true|try|un\.components|un\.custom|un\.directory|un\.instfiles|un\.license|uninstConfirm|user|Win10|Win7|Win8|WinVista|zlib)\b/, token: "builtin"},
41
41
42 // LogicLib.nsh
42 // LogicLib.nsh
43 {regex: /\$\{(?:And(?:If(?:Not)?|Unless)|Break|Case(?:Else)?|Continue|Default|Do(?:Until|While)?|Else(?:If(?:Not)?|Unless)?|End(?:If|Select|Switch)|Exit(?:Do|For|While)|For(?:Each)?|If(?:Cmd|Not(?:Then)?|Then)?|Loop(?:Until|While)?|Or(?:If(?:Not)?|Unless)|Select|Switch|Unless|While)\}/, token: "variable-2", indent: true},
43 {regex: /\$\{(?:And(?:If(?:Not)?|Unless)|Break|Case(?:Else)?|Continue|Default|Do(?:Until|While)?|Else(?:If(?:Not)?|Unless)?|End(?:If|Select|Switch)|Exit(?:Do|For|While)|For(?:Each)?|If(?:Cmd|Not(?:Then)?|Then)?|Loop(?:Until|While)?|Or(?:If(?:Not)?|Unless)|Select|Switch|Unless|While)\}/, token: "variable-2", indent: true},
@@ -71,13 +71,13 b' CodeMirror.defineSimpleMode("nsis",{'
71 {regex: /[-+\/*=<>!]+/, token: "operator"},
71 {regex: /[-+\/*=<>!]+/, token: "operator"},
72
72
73 // Variable
73 // Variable
74 {regex: /\$[\w]+/, token: "variable"},
74 {regex: /\$\w+/, token: "variable"},
75
75
76 // Constant
76 // Constant
77 {regex: /\${[\w]+}/,token: "variable-2"},
77 {regex: /\${[\w\.:-]+}/, token: "variable-2"},
78
78
79 // Language String
79 // Language String
80 {regex: /\$\([\w]+\)/,token: "variable-3"}
80 {regex: /\$\([\w\.:-]+\)/, token: "variable-3"}
81 ],
81 ],
82 comment: [
82 comment: [
83 {regex: /.*?\*\//, token: "comment", next: "start"},
83 {regex: /.*?\*\//, token: "comment", next: "start"},
@@ -1,11 +1,11 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /**********************************************************
4 /**********************************************************
5 * This script provides syntax highlighting support for
5 * This script provides syntax highlighting support for
6 * the Ntriples format.
6 * the N-Triples format.
7 * Ntriples format specification:
7 * N-Triples format specification:
8 * http://www.w3.org/TR/rdf-testcases/#ntriples
8 * https://www.w3.org/TR/n-triples/
9 ***********************************************************/
9 ***********************************************************/
10
10
11 /*
11 /*
@@ -181,6 +181,15 b' CodeMirror.defineMode("ntriples", functi'
181 };
181 };
182 });
182 });
183
183
184 // define the registered Media Type for n-triples:
185 // https://www.w3.org/TR/n-triples/#n-triples-mediatype
186 CodeMirror.defineMIME("application/n-triples", "ntriples");
187
188 // N-Quads is based on the N-Triples format (so same highlighting works)
189 // https://www.w3.org/TR/n-quads/
190 CodeMirror.defineMIME("application/n-quads", "ntriples");
191
192 // previously used, though technically incorrect media type for n-triples
184 CodeMirror.defineMIME("text/n-triples", "ntriples");
193 CodeMirror.defineMIME("text/n-triples", "ntriples");
185
194
186 });
195 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -17,7 +17,7 b' CodeMirror.defineMode("octave", function'
17 }
17 }
18
18
19 var singleOperators = new RegExp("^[\\+\\-\\*/&|\\^~<>!@'\\\\]");
19 var singleOperators = new RegExp("^[\\+\\-\\*/&|\\^~<>!@'\\\\]");
20 var singleDelimiters = new RegExp('^[\\(\\[\\{\\},:=;]');
20 var singleDelimiters = new RegExp('^[\\(\\[\\{\\},:=;\\.]');
21 var doubleOperators = new RegExp("^((==)|(~=)|(<=)|(>=)|(<<)|(>>)|(\\.[\\+\\-\\*/\\^\\\\]))");
21 var doubleOperators = new RegExp("^((==)|(~=)|(<=)|(>=)|(<<)|(>>)|(\\.[\\+\\-\\*/\\^\\\\]))");
22 var doubleDelimiters = new RegExp("^((!=)|(\\+=)|(\\-=)|(\\*=)|(/=)|(&=)|(\\|=)|(\\^=))");
22 var doubleDelimiters = new RegExp("^((!=)|(\\+=)|(\\-=)|(\\*=)|(/=)|(&=)|(\\|=)|(\\^=))");
23 var tripleDelimiters = new RegExp("^((>>=)|(<<=))");
23 var tripleDelimiters = new RegExp("^((>>=)|(<<=))");
@@ -90,8 +90,8 b' CodeMirror.defineMode("octave", function'
90 if (stream.match(wordRegexp(['nan','NaN','inf','Inf']))) { return 'number'; };
90 if (stream.match(wordRegexp(['nan','NaN','inf','Inf']))) { return 'number'; };
91
91
92 // Handle Strings
92 // Handle Strings
93 if (stream.match(/^"([^"]|(""))*"/)) { return 'string'; } ;
93 var m = stream.match(/^"(?:[^"]|"")*("|$)/) || stream.match(/^'(?:[^']|'')*('|$)/)
94 if (stream.match(/^'([^']|(''))*'/)) { return 'string'; } ;
94 if (m) { return m[1] ? 'string' : "string error"; }
95
95
96 // Handle words
96 // Handle words
97 if (stream.match(keywords)) { return 'keyword'; } ;
97 if (stream.match(keywords)) { return 'keyword'; } ;
@@ -126,7 +126,11 b' CodeMirror.defineMode("octave", function'
126 state.tokenize = tokenTranspose;
126 state.tokenize = tokenTranspose;
127 }
127 }
128 return style;
128 return style;
129 }
129 },
130
131 lineComment: '%',
132
133 fold: 'indent'
130 };
134 };
131 });
135 });
132
136
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -27,7 +27,7 b' CodeMirror.defineMode("oz", function (co'
27
27
28 var atoms = wordRegexp(["true", "false", "nil", "unit"]);
28 var atoms = wordRegexp(["true", "false", "nil", "unit"]);
29 var commonKeywords = wordRegexp(["andthen", "at", "attr", "declare", "feat", "from", "lex",
29 var commonKeywords = wordRegexp(["andthen", "at", "attr", "declare", "feat", "from", "lex",
30 "mod", "mode", "orelse", "parser", "prod", "prop", "scanner", "self", "syn", "token"]);
30 "mod", "div", "mode", "orelse", "parser", "prod", "prop", "scanner", "self", "syn", "token"]);
31 var openingKeywords = wordRegexp(["local", "proc", "fun", "case", "class", "if", "cond", "or", "dis",
31 var openingKeywords = wordRegexp(["local", "proc", "fun", "case", "class", "if", "cond", "or", "dis",
32 "choice", "not", "thread", "try", "raise", "lock", "for", "suchthat", "meth", "functor"]);
32 "choice", "not", "thread", "try", "raise", "lock", "for", "suchthat", "meth", "functor"]);
33 var middleKeywords = wordRegexp(middle);
33 var middleKeywords = wordRegexp(middle);
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -17,9 +17,21 b' CodeMirror.defineMode("pascal", function'
17 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
17 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
18 return obj;
18 return obj;
19 }
19 }
20 var keywords = words("and array begin case const div do downto else end file for forward integer " +
20 var keywords = words(
21 "boolean char function goto if in label mod nil not of or packed procedure " +
21 "absolute and array asm begin case const constructor destructor div do " +
22 "program record repeat set string then to type until var while with");
22 "downto else end file for function goto if implementation in inherited " +
23 "inline interface label mod nil not object of operator or packed procedure " +
24 "program record reintroduce repeat self set shl shr string then to type " +
25 "unit until uses var while with xor as class dispinterface except exports " +
26 "finalization finally initialization inline is library on out packed " +
27 "property raise resourcestring threadvar try absolute abstract alias " +
28 "assembler bitpacked break cdecl continue cppdecl cvar default deprecated " +
29 "dynamic enumerator experimental export external far far16 forward generic " +
30 "helper implements index interrupt iocheck local message name near " +
31 "nodefault noreturn nostackframe oldfpccall otherwise overload override " +
32 "pascal platform private protected public published read register " +
33 "reintroduce result safecall saveregisters softfloat specialize static " +
34 "stdcall stored strict unaligned unimplemented varargs virtual write");
23 var atoms = {"null": true};
35 var atoms = {"null": true};
24
36
25 var isOperatorChar = /[+\-*&%=<>!?|\/]/;
37 var isOperatorChar = /[+\-*&%=<>!?|\/]/;
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -24,7 +24,7 b' CodeMirror.defineMode("pegjs", function '
24 inString: false,
24 inString: false,
25 stringType: null,
25 stringType: null,
26 inComment: false,
26 inComment: false,
27 inChracterClass: false,
27 inCharacterClass: false,
28 braced: 0,
28 braced: 0,
29 lhs: true,
29 lhs: true,
30 localState: null
30 localState: null
@@ -66,22 +66,22 b' CodeMirror.defineMode("pegjs", function '
66 }
66 }
67 }
67 }
68 return "comment";
68 return "comment";
69 } else if (state.inChracterClass) {
69 } else if (state.inCharacterClass) {
70 while (state.inChracterClass && !stream.eol()) {
70 while (state.inCharacterClass && !stream.eol()) {
71 if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) {
71 if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) {
72 state.inChracterClass = false;
72 state.inCharacterClass = false;
73 }
73 }
74 }
74 }
75 } else if (stream.peek() === '[') {
75 } else if (stream.peek() === '[') {
76 stream.next();
76 stream.next();
77 state.inChracterClass = true;
77 state.inCharacterClass = true;
78 return 'bracket';
78 return 'bracket';
79 } else if (stream.match(/^\/\//)) {
79 } else if (stream.match(/^\/\//)) {
80 stream.skipToEnd();
80 stream.skipToEnd();
81 return "comment";
81 return "comment";
82 } else if (state.braced || stream.peek() === '{') {
82 } else if (state.braced || stream.peek() === '{') {
83 if (state.localState === null) {
83 if (state.localState === null) {
84 state.localState = jsMode.startState();
84 state.localState = CodeMirror.startState(jsMode);
85 }
85 }
86 var token = jsMode.token(stream, state.localState);
86 var token = jsMode.token(stream, state.localState);
87 var text = stream.current();
87 var text = stream.current();
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
4 // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
5 // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
5 // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
@@ -268,7 +268,7 b' CodeMirror.defineMode("perl",function(){'
268 chmod :1, // - changes the permissions on a list of files
268 chmod :1, // - changes the permissions on a list of files
269 chomp :1, // - remove a trailing record separator from a string
269 chomp :1, // - remove a trailing record separator from a string
270 chop :1, // - remove the last character from a string
270 chop :1, // - remove the last character from a string
271 chown :1, // - change the owership on a list of files
271 chown :1, // - change the ownership on a list of files
272 chr :1, // - get character this number represents
272 chr :1, // - get character this number represents
273 chroot :1, // - make directory new root for path lookups
273 chroot :1, // - make directory new root for path lookups
274 close :1, // - close file (or pipe or socket) handle
274 close :1, // - close file (or pipe or socket) handle
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -86,7 +86,7 b''
86 "die echo empty exit eval include include_once isset list require require_once return " +
86 "die echo empty exit eval include include_once isset list require require_once return " +
87 "print unset __halt_compiler self static parent yield insteadof finally";
87 "print unset __halt_compiler self static parent yield insteadof finally";
88 var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__";
88 var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__";
89 var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents file_put_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count";
89 var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents file_put_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists array_intersect_key array_combine array_column pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count";
90 CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" "));
90 CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" "));
91 CodeMirror.registerHelper("wordChars", "php", /[\w$]/);
91 CodeMirror.registerHelper("wordChars", "php", /[\w$]/);
92
92
@@ -151,7 +151,7 b''
151 };
151 };
152
152
153 CodeMirror.defineMode("php", function(config, parserConfig) {
153 CodeMirror.defineMode("php", function(config, parserConfig) {
154 var htmlMode = CodeMirror.getMode(config, "text/html");
154 var htmlMode = CodeMirror.getMode(config, (parserConfig && parserConfig.htmlMode) || "text/html");
155 var phpMode = CodeMirror.getMode(config, phpConfig);
155 var phpMode = CodeMirror.getMode(config, phpConfig);
156
156
157 function dispatch(stream, state) {
157 function dispatch(stream, state) {
@@ -160,7 +160,7 b''
160 if (!isPHP) {
160 if (!isPHP) {
161 if (stream.match(/^<\?\w*/)) {
161 if (stream.match(/^<\?\w*/)) {
162 state.curMode = phpMode;
162 state.curMode = phpMode;
163 if (!state.php) state.php = CodeMirror.startState(phpMode, htmlMode.indent(state.html, ""))
163 if (!state.php) state.php = CodeMirror.startState(phpMode, htmlMode.indent(state.html, "", ""))
164 state.curState = state.php;
164 state.curState = state.php;
165 return "meta";
165 return "meta";
166 }
166 }
@@ -213,11 +213,11 b''
213
213
214 token: dispatch,
214 token: dispatch,
215
215
216 indent: function(state, textAfter) {
216 indent: function(state, textAfter, line) {
217 if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
217 if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
218 (state.curMode == phpMode && /^\?>/.test(textAfter)))
218 (state.curMode == phpMode && /^\?>/.test(textAfter)))
219 return htmlMode.indent(state.html, textAfter);
219 return htmlMode.indent(state.html, textAfter, line);
220 return state.curMode.indent(state.curState, textAfter);
220 return state.curMode.indent(state.curState, textAfter, line);
221 },
221 },
222
222
223 blockCommentStart: "/*",
223 blockCommentStart: "/*",
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /*
4 /*
5 * Pig Latin Mode for CodeMirror 2
5 * Pig Latin Mode for CodeMirror 2
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -34,7 +34,7 b' CodeMirror.defineMode("properties", func'
34 }
34 }
35
35
36 if (sol) {
36 if (sol) {
37 while(stream.eatSpace());
37 while(stream.eatSpace()) {}
38 }
38 }
39
39
40 var ch = stream.next();
40 var ch = stream.next();
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -126,7 +126,7 b' CodeMirror.defineMode("puppet", function'
126 if (word && words.hasOwnProperty(word)) {
126 if (word && words.hasOwnProperty(word)) {
127 // Negates the initial next()
127 // Negates the initial next()
128 stream.backUp(1);
128 stream.backUp(1);
129 // Acutally move the stream
129 // rs move the stream
130 stream.match(/[\w]+/);
130 stream.match(/[\w]+/);
131 // We want to process these words differently
131 // We want to process these words differently
132 // do to the importance they have in Puppet
132 // do to the importance they have in Puppet
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -32,13 +32,6 b''
32 "sorted", "staticmethod", "str", "sum", "super", "tuple",
32 "sorted", "staticmethod", "str", "sum", "super", "tuple",
33 "type", "vars", "zip", "__import__", "NotImplemented",
33 "type", "vars", "zip", "__import__", "NotImplemented",
34 "Ellipsis", "__debug__"];
34 "Ellipsis", "__debug__"];
35 var py2 = {builtins: ["apply", "basestring", "buffer", "cmp", "coerce", "execfile",
36 "file", "intern", "long", "raw_input", "reduce", "reload",
37 "unichr", "unicode", "xrange", "False", "True", "None"],
38 keywords: ["exec", "print"]};
39 var py3 = {builtins: ["ascii", "bytes", "exec", "print"],
40 keywords: ["nonlocal", "False", "True", "None", "async", "await"]};
41
42 CodeMirror.registerHelper("hintWords", "python", commonKeywords.concat(commonBuiltins));
35 CodeMirror.registerHelper("hintWords", "python", commonKeywords.concat(commonBuiltins));
43
36
44 function top(state) {
37 function top(state) {
@@ -48,51 +41,51 b''
48 CodeMirror.defineMode("python", function(conf, parserConf) {
41 CodeMirror.defineMode("python", function(conf, parserConf) {
49 var ERRORCLASS = "error";
42 var ERRORCLASS = "error";
50
43
51 var singleDelimiters = parserConf.singleDelimiters || /^[\(\)\[\]\{\}@,:`=;\.]/;
44 var delimiters = parserConf.delimiters || parserConf.singleDelimiters || /^[\(\)\[\]\{\}@,:`=;\.\\]/;
52 var doubleOperators = parserConf.doubleOperators || /^([!<>]==|<>|<<|>>|\/\/|\*\*)/;
45 // (Backwards-compatiblity with old, cumbersome config system)
53 var doubleDelimiters = parserConf.doubleDelimiters || /^(\+=|\-=|\*=|%=|\/=|&=|\|=|\^=)/;
46 var operators = [parserConf.singleOperators, parserConf.doubleOperators, parserConf.doubleDelimiters, parserConf.tripleDelimiters,
54 var tripleDelimiters = parserConf.tripleDelimiters || /^(\/\/=|>>=|<<=|\*\*=)/;
47 parserConf.operators || /^([-+*/%\/&|^]=?|[<>=]+|\/\/=?|\*\*=?|!=|[~!@]|\.\.\.)/]
55
48 for (var i = 0; i < operators.length; i++) if (!operators[i]) operators.splice(i--, 1)
56 if (parserConf.version && parseInt(parserConf.version, 10) == 3){
57 // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator
58 var singleOperators = parserConf.singleOperators || /^[\+\-\*\/%&|\^~<>!@]/;
59 var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*/;
60 } else {
61 var singleOperators = parserConf.singleOperators || /^[\+\-\*\/%&|\^~<>!]/;
62 var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*/;
63 }
64
49
65 var hangingIndent = parserConf.hangingIndent || conf.indentUnit;
50 var hangingIndent = parserConf.hangingIndent || conf.indentUnit;
66
51
67 var myKeywords = commonKeywords, myBuiltins = commonBuiltins;
52 var myKeywords = commonKeywords, myBuiltins = commonBuiltins;
68 if(parserConf.extra_keywords != undefined){
53 if (parserConf.extra_keywords != undefined)
69 myKeywords = myKeywords.concat(parserConf.extra_keywords);
54 myKeywords = myKeywords.concat(parserConf.extra_keywords);
70 }
55
71 if(parserConf.extra_builtins != undefined){
56 if (parserConf.extra_builtins != undefined)
72 myBuiltins = myBuiltins.concat(parserConf.extra_builtins);
57 myBuiltins = myBuiltins.concat(parserConf.extra_builtins);
73 }
58
74 if (parserConf.version && parseInt(parserConf.version, 10) == 3) {
59 var py3 = !(parserConf.version && Number(parserConf.version) < 3)
75 myKeywords = myKeywords.concat(py3.keywords);
60 if (py3) {
76 myBuiltins = myBuiltins.concat(py3.builtins);
61 // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator
77 var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
62 var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*/;
63 myKeywords = myKeywords.concat(["nonlocal", "False", "True", "None", "async", "await"]);
64 myBuiltins = myBuiltins.concat(["ascii", "bytes", "exec", "print"]);
65 var stringPrefixes = new RegExp("^(([rbuf]|(br)|(fr))?('{3}|\"{3}|['\"]))", "i");
78 } else {
66 } else {
79 myKeywords = myKeywords.concat(py2.keywords);
67 var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*/;
80 myBuiltins = myBuiltins.concat(py2.builtins);
68 myKeywords = myKeywords.concat(["exec", "print"]);
81 var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
69 myBuiltins = myBuiltins.concat(["apply", "basestring", "buffer", "cmp", "coerce", "execfile",
70 "file", "intern", "long", "raw_input", "reduce", "reload",
71 "unichr", "unicode", "xrange", "False", "True", "None"]);
72 var stringPrefixes = new RegExp("^(([rubf]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
82 }
73 }
83 var keywords = wordRegexp(myKeywords);
74 var keywords = wordRegexp(myKeywords);
84 var builtins = wordRegexp(myBuiltins);
75 var builtins = wordRegexp(myBuiltins);
85
76
86 // tokenizers
77 // tokenizers
87 function tokenBase(stream, state) {
78 function tokenBase(stream, state) {
79 var sol = stream.sol() && state.lastToken != "\\"
80 if (sol) state.indent = stream.indentation()
88 // Handle scope changes
81 // Handle scope changes
89 if (stream.sol() && top(state).type == "py") {
82 if (sol && top(state).type == "py") {
90 var scopeOffset = top(state).offset;
83 var scopeOffset = top(state).offset;
91 if (stream.eatSpace()) {
84 if (stream.eatSpace()) {
92 var lineOffset = stream.indentation();
85 var lineOffset = stream.indentation();
93 if (lineOffset > scopeOffset)
86 if (lineOffset > scopeOffset)
94 pushScope(stream, state, "py");
87 pushPyScope(state);
95 else if (lineOffset < scopeOffset && dedent(stream, state))
88 else if (lineOffset < scopeOffset && dedent(stream, state) && stream.peek() != "#")
96 state.errorToken = true;
89 state.errorToken = true;
97 return null;
90 return null;
98 } else {
91 } else {
@@ -108,20 +101,15 b''
108 function tokenBaseInner(stream, state) {
101 function tokenBaseInner(stream, state) {
109 if (stream.eatSpace()) return null;
102 if (stream.eatSpace()) return null;
110
103
111 var ch = stream.peek();
112
113 // Handle Comments
104 // Handle Comments
114 if (ch == "#") {
105 if (stream.match(/^#.*/)) return "comment";
115 stream.skipToEnd();
116 return "comment";
117 }
118
106
119 // Handle Number Literals
107 // Handle Number Literals
120 if (stream.match(/^[0-9\.]/, false)) {
108 if (stream.match(/^[0-9\.]/, false)) {
121 var floatLiteral = false;
109 var floatLiteral = false;
122 // Floats
110 // Floats
123 if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
111 if (stream.match(/^[\d_]*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
124 if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
112 if (stream.match(/^[\d_]+\.\d*/)) { floatLiteral = true; }
125 if (stream.match(/^\.\d+/)) { floatLiteral = true; }
113 if (stream.match(/^\.\d+/)) { floatLiteral = true; }
126 if (floatLiteral) {
114 if (floatLiteral) {
127 // Float literals may be "imaginary"
115 // Float literals may be "imaginary"
@@ -131,13 +119,13 b''
131 // Integers
119 // Integers
132 var intLiteral = false;
120 var intLiteral = false;
133 // Hex
121 // Hex
134 if (stream.match(/^0x[0-9a-f]+/i)) intLiteral = true;
122 if (stream.match(/^0x[0-9a-f_]+/i)) intLiteral = true;
135 // Binary
123 // Binary
136 if (stream.match(/^0b[01]+/i)) intLiteral = true;
124 if (stream.match(/^0b[01_]+/i)) intLiteral = true;
137 // Octal
125 // Octal
138 if (stream.match(/^0o[0-7]+/i)) intLiteral = true;
126 if (stream.match(/^0o[0-7_]+/i)) intLiteral = true;
139 // Decimal
127 // Decimal
140 if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
128 if (stream.match(/^[1-9][\d_]*(e[\+\-]?[\d_]+)?/)) {
141 // Decimal literals may be "imaginary"
129 // Decimal literals may be "imaginary"
142 stream.eat(/J/i);
130 stream.eat(/J/i);
143 // TODO - Can you have imaginary longs?
131 // TODO - Can you have imaginary longs?
@@ -154,19 +142,20 b''
154
142
155 // Handle Strings
143 // Handle Strings
156 if (stream.match(stringPrefixes)) {
144 if (stream.match(stringPrefixes)) {
157 state.tokenize = tokenStringFactory(stream.current());
145 var isFmtString = stream.current().toLowerCase().indexOf('f') !== -1;
146 if (!isFmtString) {
147 state.tokenize = tokenStringFactory(stream.current(), state.tokenize);
158 return state.tokenize(stream, state);
148 return state.tokenize(stream, state);
149 } else {
150 state.tokenize = formatStringFactory(stream.current(), state.tokenize);
151 return state.tokenize(stream, state);
152 }
159 }
153 }
160
154
161 // Handle operators and Delimiters
155 for (var i = 0; i < operators.length; i++)
162 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters))
156 if (stream.match(operators[i])) return "operator"
163 return "punctuation";
164
157
165 if (stream.match(doubleOperators) || stream.match(singleOperators))
158 if (stream.match(delimiters)) return "punctuation";
166 return "operator";
167
168 if (stream.match(singleDelimiters))
169 return "punctuation";
170
159
171 if (state.lastToken == "." && stream.match(identifiers))
160 if (state.lastToken == "." && stream.match(identifiers))
172 return "property";
161 return "property";
@@ -191,8 +180,69 b''
191 return ERRORCLASS;
180 return ERRORCLASS;
192 }
181 }
193
182
194 function tokenStringFactory(delimiter) {
183 function formatStringFactory(delimiter, tokenOuter) {
195 while ("rub".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)
184 while ("rubf".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)
185 delimiter = delimiter.substr(1);
186
187 var singleline = delimiter.length == 1;
188 var OUTCLASS = "string";
189
190 function tokenNestedExpr(depth) {
191 return function(stream, state) {
192 var inner = tokenBaseInner(stream, state)
193 if (inner == "punctuation") {
194 if (stream.current() == "{") {
195 state.tokenize = tokenNestedExpr(depth + 1)
196 } else if (stream.current() == "}") {
197 if (depth > 1) state.tokenize = tokenNestedExpr(depth - 1)
198 else state.tokenize = tokenString
199 }
200 }
201 return inner
202 }
203 }
204
205 function tokenString(stream, state) {
206 while (!stream.eol()) {
207 stream.eatWhile(/[^'"\{\}\\]/);
208 if (stream.eat("\\")) {
209 stream.next();
210 if (singleline && stream.eol())
211 return OUTCLASS;
212 } else if (stream.match(delimiter)) {
213 state.tokenize = tokenOuter;
214 return OUTCLASS;
215 } else if (stream.match('{{')) {
216 // ignore {{ in f-str
217 return OUTCLASS;
218 } else if (stream.match('{', false)) {
219 // switch to nested mode
220 state.tokenize = tokenNestedExpr(0)
221 if (stream.current()) return OUTCLASS;
222 else return state.tokenize(stream, state)
223 } else if (stream.match('}}')) {
224 return OUTCLASS;
225 } else if (stream.match('}')) {
226 // single } in f-string is an error
227 return ERRORCLASS;
228 } else {
229 stream.eat(/['"]/);
230 }
231 }
232 if (singleline) {
233 if (parserConf.singleLineStringErrors)
234 return ERRORCLASS;
235 else
236 state.tokenize = tokenOuter;
237 }
238 return OUTCLASS;
239 }
240 tokenString.isString = true;
241 return tokenString;
242 }
243
244 function tokenStringFactory(delimiter, tokenOuter) {
245 while ("rubf".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)
196 delimiter = delimiter.substr(1);
246 delimiter = delimiter.substr(1);
197
247
198 var singleline = delimiter.length == 1;
248 var singleline = delimiter.length == 1;
@@ -206,7 +256,7 b''
206 if (singleline && stream.eol())
256 if (singleline && stream.eol())
207 return OUTCLASS;
257 return OUTCLASS;
208 } else if (stream.match(delimiter)) {
258 } else if (stream.match(delimiter)) {
209 state.tokenize = tokenBase;
259 state.tokenize = tokenOuter;
210 return OUTCLASS;
260 return OUTCLASS;
211 } else {
261 } else {
212 stream.eat(/['"]/);
262 stream.eat(/['"]/);
@@ -216,7 +266,7 b''
216 if (parserConf.singleLineStringErrors)
266 if (parserConf.singleLineStringErrors)
217 return ERRORCLASS;
267 return ERRORCLASS;
218 else
268 else
219 state.tokenize = tokenBase;
269 state.tokenize = tokenOuter;
220 }
270 }
221 return OUTCLASS;
271 return OUTCLASS;
222 }
272 }
@@ -224,21 +274,23 b''
224 return tokenString;
274 return tokenString;
225 }
275 }
226
276
227 function pushScope(stream, state, type) {
277 function pushPyScope(state) {
228 var offset = 0, align = null;
278 while (top(state).type != "py") state.scopes.pop()
229 if (type == "py") {
279 state.scopes.push({offset: top(state).offset + conf.indentUnit,
230 while (top(state).type != "py")
280 type: "py",
231 state.scopes.pop();
281 align: null})
232 }
282 }
233 offset = top(state).offset + (type == "py" ? conf.indentUnit : hangingIndent);
283
234 if (type != "py" && !stream.match(/^(\s|#.*)*$/, false))
284 function pushBracketScope(stream, state, type) {
235 align = stream.column() + 1;
285 var align = stream.match(/^([\s\[\{\(]|#.*)*$/, false) ? null : stream.column() + 1
236 state.scopes.push({offset: offset, type: type, align: align});
286 state.scopes.push({offset: state.indent + hangingIndent,
287 type: type,
288 align: align})
237 }
289 }
238
290
239 function dedent(stream, state) {
291 function dedent(stream, state) {
240 var indented = stream.indentation();
292 var indented = stream.indentation();
241 while (top(state).offset > indented) {
293 while (state.scopes.length > 1 && top(state).offset > indented) {
242 if (top(state).type != "py") return true;
294 if (top(state).type != "py") return true;
243 state.scopes.pop();
295 state.scopes.pop();
244 }
296 }
@@ -246,17 +298,16 b''
246 }
298 }
247
299
248 function tokenLexer(stream, state) {
300 function tokenLexer(stream, state) {
301 if (stream.sol()) state.beginningOfLine = true;
302
249 var style = state.tokenize(stream, state);
303 var style = state.tokenize(stream, state);
250 var current = stream.current();
304 var current = stream.current();
251
305
252 // Handle decorators
306 // Handle decorators
253 if (current == "@"){
307 if (state.beginningOfLine && current == "@")
254 if(parserConf.version && parseInt(parserConf.version, 10) == 3){
308 return stream.match(identifiers, false) ? "meta" : py3 ? "operator" : ERRORCLASS;
255 return stream.match(identifiers, false) ? "meta" : "operator";
309
256 } else {
310 if (/\S/.test(current)) state.beginningOfLine = false;
257 return stream.match(identifiers, false) ? "meta" : ERRORCLASS;
258 }
259 }
260
311
261 if ((style == "variable" || style == "builtin")
312 if ((style == "variable" || style == "builtin")
262 && state.lastToken == "meta")
313 && state.lastToken == "meta")
@@ -268,17 +319,19 b''
268
319
269 if (current == "lambda") state.lambda = true;
320 if (current == "lambda") state.lambda = true;
270 if (current == ":" && !state.lambda && top(state).type == "py")
321 if (current == ":" && !state.lambda && top(state).type == "py")
271 pushScope(stream, state, "py");
322 pushPyScope(state);
272
323
273 var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1;
324 if (current.length == 1 && !/string|comment/.test(style)) {
325 var delimiter_index = "[({".indexOf(current);
274 if (delimiter_index != -1)
326 if (delimiter_index != -1)
275 pushScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
327 pushBracketScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
276
328
277 delimiter_index = "])}".indexOf(current);
329 delimiter_index = "])}".indexOf(current);
278 if (delimiter_index != -1) {
330 if (delimiter_index != -1) {
279 if (top(state).type == current) state.scopes.pop();
331 if (top(state).type == current) state.indent = state.scopes.pop().offset - hangingIndent
280 else return ERRORCLASS;
332 else return ERRORCLASS;
281 }
333 }
334 }
282 if (state.dedent > 0 && stream.eol() && top(state).type == "py") {
335 if (state.dedent > 0 && stream.eol() && top(state).type == "py") {
283 if (state.scopes.length > 1) state.scopes.pop();
336 if (state.scopes.length > 1) state.scopes.pop();
284 state.dedent -= 1;
337 state.dedent -= 1;
@@ -292,6 +345,7 b''
292 return {
345 return {
293 tokenize: tokenBase,
346 tokenize: tokenBase,
294 scopes: [{offset: basecolumn || 0, type: "py", align: null}],
347 scopes: [{offset: basecolumn || 0, type: "py", align: null}],
348 indent: basecolumn || 0,
295 lastToken: null,
349 lastToken: null,
296 lambda: false,
350 lambda: false,
297 dedent: 0
351 dedent: 0
@@ -316,16 +370,14 b''
316 if (state.tokenize != tokenBase)
370 if (state.tokenize != tokenBase)
317 return state.tokenize.isString ? CodeMirror.Pass : 0;
371 return state.tokenize.isString ? CodeMirror.Pass : 0;
318
372
319 var scope = top(state);
373 var scope = top(state), closing = scope.type == textAfter.charAt(0)
320 var closing = textAfter && textAfter.charAt(0) == scope.type;
321 if (scope.align != null)
374 if (scope.align != null)
322 return scope.align - (closing ? 1 : 0);
375 return scope.align - (closing ? 1 : 0)
323 else if (closing && state.scopes.length > 1)
324 return state.scopes[state.scopes.length - 2].offset;
325 else
376 else
326 return scope.offset;
377 return scope.offset - (closing ? hangingIndent : 0)
327 },
378 },
328
379
380 electricInput: /^\s*[\}\]\)]$/,
329 closeBrackets: {triples: "'\""},
381 closeBrackets: {triples: "'\""},
330 lineComment: "#",
382 lineComment: "#",
331 fold: "indent"
383 fold: "indent"
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -25,7 +25,7 b' CodeMirror.defineMode("q",function(confi'
25 return(state.tokenize=tokenLineComment)(stream,state);
25 return(state.tokenize=tokenLineComment)(stream,state);
26 else if(c=="\\"){
26 else if(c=="\\"){
27 if(stream.eol()||/\s/.test(stream.peek()))
27 if(stream.eol()||/\s/.test(stream.peek()))
28 return stream.skipToEnd(),/^\\\s*$/.test(stream.current())?(state.tokenize=tokenCommentToEOF)(stream, state):state.tokenize=tokenBase,"comment";
28 return stream.skipToEnd(),/^\\\s*$/.test(stream.current())?(state.tokenize=tokenCommentToEOF)(stream):state.tokenize=tokenBase,"comment";
29 else
29 else
30 return state.tokenize=tokenBase,"builtin";
30 return state.tokenize=tokenBase,"builtin";
31 }
31 }
@@ -34,25 +34,25 b' CodeMirror.defineMode("q",function(confi'
34 if(c=='"')
34 if(c=='"')
35 return(state.tokenize=tokenString)(stream,state);
35 return(state.tokenize=tokenString)(stream,state);
36 if(c=='`')
36 if(c=='`')
37 return stream.eatWhile(/[A-Z|a-z|\d|_|:|\/|\.]/),"symbol";
37 return stream.eatWhile(/[A-Za-z\d_:\/.]/),"symbol";
38 if(("."==c&&/\d/.test(stream.peek()))||/\d/.test(c)){
38 if(("."==c&&/\d/.test(stream.peek()))||/\d/.test(c)){
39 var t=null;
39 var t=null;
40 stream.backUp(1);
40 stream.backUp(1);
41 if(stream.match(/^\d{4}\.\d{2}(m|\.\d{2}([D|T](\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)?)?)/)
41 if(stream.match(/^\d{4}\.\d{2}(m|\.\d{2}([DT](\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)?)?)/)
42 || stream.match(/^\d+D(\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)/)
42 || stream.match(/^\d+D(\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)/)
43 || stream.match(/^\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?/)
43 || stream.match(/^\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?/)
44 || stream.match(/^\d+[ptuv]{1}/))
44 || stream.match(/^\d+[ptuv]{1}/))
45 t="temporal";
45 t="temporal";
46 else if(stream.match(/^0[NwW]{1}/)
46 else if(stream.match(/^0[NwW]{1}/)
47 || stream.match(/^0x[\d|a-f|A-F]*/)
47 || stream.match(/^0x[\da-fA-F]*/)
48 || stream.match(/^[0|1]+[b]{1}/)
48 || stream.match(/^[01]+[b]{1}/)
49 || stream.match(/^\d+[chijn]{1}/)
49 || stream.match(/^\d+[chijn]{1}/)
50 || stream.match(/-?\d*(\.\d*)?(e[+\-]?\d+)?(e|f)?/))
50 || stream.match(/-?\d*(\.\d*)?(e[+\-]?\d+)?(e|f)?/))
51 t="number";
51 t="number";
52 return(t&&(!(c=stream.peek())||E.test(c)))?t:(stream.next(),"error");
52 return(t&&(!(c=stream.peek())||E.test(c)))?t:(stream.next(),"error");
53 }
53 }
54 if(/[A-Z|a-z]|\./.test(c))
54 if(/[A-Za-z]|\./.test(c))
55 return stream.eatWhile(/[A-Z|a-z|\.|_|\d]/),keywords.test(stream.current())?"keyword":"variable";
55 return stream.eatWhile(/[A-Za-z._\d]/),keywords.test(stream.current())?"keyword":"variable";
56 if(/[|/&^!+:\\\-*%$=~#;@><\.,?_\']/.test(c))
56 if(/[|/&^!+:\\\-*%$=~#;@><\.,?_\']/.test(c))
57 return null;
57 return null;
58 if(/[{}\(\[\]\)]/.test(c))
58 if(/[{}\(\[\]\)]/.test(c))
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -11,16 +11,25 b''
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 CodeMirror.registerHelper("wordChars", "r", /[\w.]/);
15
14 CodeMirror.defineMode("r", function(config) {
16 CodeMirror.defineMode("r", function(config) {
15 function wordObj(str) {
17 function wordObj(words) {
16 var words = str.split(" "), res = {};
18 var res = {};
17 for (var i = 0; i < words.length; ++i) res[words[i]] = true;
19 for (var i = 0; i < words.length; ++i) res[words[i]] = true;
18 return res;
20 return res;
19 }
21 }
20 var atoms = wordObj("NULL NA Inf NaN NA_integer_ NA_real_ NA_complex_ NA_character_");
22 var commonAtoms = ["NULL", "NA", "Inf", "NaN", "NA_integer_", "NA_real_", "NA_complex_", "NA_character_", "TRUE", "FALSE"];
21 var builtins = wordObj("list quote bquote eval return call parse deparse");
23 var commonBuiltins = ["list", "quote", "bquote", "eval", "return", "call", "parse", "deparse"];
22 var keywords = wordObj("if else repeat while function for in next break");
24 var commonKeywords = ["if", "else", "repeat", "while", "function", "for", "in", "next", "break"];
23 var blockkeywords = wordObj("if else repeat while function for");
25 var commonBlockKeywords = ["if", "else", "repeat", "while", "function", "for"];
26
27 CodeMirror.registerHelper("hintWords", "r", commonAtoms.concat(commonBuiltins, commonKeywords));
28
29 var atoms = wordObj(commonAtoms);
30 var builtins = wordObj(commonBuiltins);
31 var keywords = wordObj(commonKeywords);
32 var blockkeywords = wordObj(commonBlockKeywords);
24 var opChars = /[+\-*\/^<>=!&|~$:]/;
33 var opChars = /[+\-*\/^<>=!&|~$:]/;
25 var curPunc;
34 var curPunc;
26
35
@@ -42,6 +51,9 b' CodeMirror.defineMode("r", function(conf'
42 } else if (ch == "'" || ch == '"') {
51 } else if (ch == "'" || ch == '"') {
43 state.tokenize = tokenString(ch);
52 state.tokenize = tokenString(ch);
44 return "string";
53 return "string";
54 } else if (ch == "`") {
55 stream.match(/[^`]+`/);
56 return "variable-3";
45 } else if (ch == "." && stream.match(/.[.\d]+/)) {
57 } else if (ch == "." && stream.match(/.[.\d]+/)) {
46 return "keyword";
58 return "keyword";
47 } else if (/[\w\.]/.test(ch) && ch != "_") {
59 } else if (/[\w\.]/.test(ch) && ch != "_") {
@@ -60,13 +72,17 b' CodeMirror.defineMode("r", function(conf'
60 return "variable";
72 return "variable";
61 } else if (ch == "%") {
73 } else if (ch == "%") {
62 if (stream.skipTo("%")) stream.next();
74 if (stream.skipTo("%")) stream.next();
63 return "variable-2";
75 return "operator variable-2";
64 } else if (ch == "<" && stream.eat("-")) {
76 } else if (
65 return "arrow";
77 (ch == "<" && stream.eat("-")) ||
78 (ch == "<" && stream.match("<-")) ||
79 (ch == "-" && stream.match(/>>?/))
80 ) {
81 return "operator arrow";
66 } else if (ch == "=" && state.ctx.argList) {
82 } else if (ch == "=" && state.ctx.argList) {
67 return "arg-is";
83 return "arg-is";
68 } else if (opChars.test(ch)) {
84 } else if (opChars.test(ch)) {
69 if (ch == "$") return "dollar";
85 if (ch == "$") return "operator dollar";
70 stream.eatWhile(opChars);
86 stream.eatWhile(opChars);
71 return "operator";
87 return "operator";
72 } else if (/[\(\){}\[\];]/.test(ch)) {
88 } else if (/[\(\){}\[\];]/.test(ch)) {
@@ -99,13 +115,23 b' CodeMirror.defineMode("r", function(conf'
99 };
115 };
100 }
116 }
101
117
118 var ALIGN_YES = 1, ALIGN_NO = 2, BRACELESS = 4
119
102 function push(state, type, stream) {
120 function push(state, type, stream) {
103 state.ctx = {type: type,
121 state.ctx = {type: type,
104 indent: state.indent,
122 indent: state.indent,
105 align: null,
123 flags: 0,
106 column: stream.column(),
124 column: stream.column(),
107 prev: state.ctx};
125 prev: state.ctx};
108 }
126 }
127 function setFlag(state, flag) {
128 var ctx = state.ctx
129 state.ctx = {type: ctx.type,
130 indent: ctx.indent,
131 flags: ctx.flags | flag,
132 column: ctx.column,
133 prev: ctx.prev}
134 }
109 function pop(state) {
135 function pop(state) {
110 state.indent = state.ctx.indent;
136 state.indent = state.ctx.indent;
111 state.ctx = state.ctx.prev;
137 state.ctx = state.ctx.prev;
@@ -116,22 +142,22 b' CodeMirror.defineMode("r", function(conf'
116 return {tokenize: tokenBase,
142 return {tokenize: tokenBase,
117 ctx: {type: "top",
143 ctx: {type: "top",
118 indent: -config.indentUnit,
144 indent: -config.indentUnit,
119 align: false},
145 flags: ALIGN_NO},
120 indent: 0,
146 indent: 0,
121 afterIdent: false};
147 afterIdent: false};
122 },
148 },
123
149
124 token: function(stream, state) {
150 token: function(stream, state) {
125 if (stream.sol()) {
151 if (stream.sol()) {
126 if (state.ctx.align == null) state.ctx.align = false;
152 if ((state.ctx.flags & 3) == 0) state.ctx.flags |= ALIGN_NO
153 if (state.ctx.flags & BRACELESS) pop(state)
127 state.indent = stream.indentation();
154 state.indent = stream.indentation();
128 }
155 }
129 if (stream.eatSpace()) return null;
156 if (stream.eatSpace()) return null;
130 var style = state.tokenize(stream, state);
157 var style = state.tokenize(stream, state);
131 if (style != "comment" && state.ctx.align == null) state.ctx.align = true;
158 if (style != "comment" && (state.ctx.flags & ALIGN_NO) == 0) setFlag(state, ALIGN_YES)
132
159
133 var ctype = state.ctx.type;
160 if ((curPunc == ";" || curPunc == "{" || curPunc == "}") && state.ctx.type == "block") pop(state);
134 if ((curPunc == ";" || curPunc == "{" || curPunc == "}") && ctype == "block") pop(state);
135 if (curPunc == "{") push(state, "}", stream);
161 if (curPunc == "{") push(state, "}", stream);
136 else if (curPunc == "(") {
162 else if (curPunc == "(") {
137 push(state, ")", stream);
163 push(state, ")", stream);
@@ -139,7 +165,8 b' CodeMirror.defineMode("r", function(conf'
139 }
165 }
140 else if (curPunc == "[") push(state, "]", stream);
166 else if (curPunc == "[") push(state, "]", stream);
141 else if (curPunc == "block") push(state, "block", stream);
167 else if (curPunc == "block") push(state, "block", stream);
142 else if (curPunc == ctype) pop(state);
168 else if (curPunc == state.ctx.type) pop(state);
169 else if (state.ctx.type == "block" && style != "comment") setFlag(state, BRACELESS)
143 state.afterIdent = style == "variable" || style == "keyword";
170 state.afterIdent = style == "variable" || style == "keyword";
144 return style;
171 return style;
145 },
172 },
@@ -148,8 +175,9 b' CodeMirror.defineMode("r", function(conf'
148 if (state.tokenize != tokenBase) return 0;
175 if (state.tokenize != tokenBase) return 0;
149 var firstChar = textAfter && textAfter.charAt(0), ctx = state.ctx,
176 var firstChar = textAfter && textAfter.charAt(0), ctx = state.ctx,
150 closing = firstChar == ctx.type;
177 closing = firstChar == ctx.type;
178 if (ctx.flags & BRACELESS) ctx = ctx.prev
151 if (ctx.type == "block") return ctx.indent + (firstChar == "{" ? 0 : config.indentUnit);
179 if (ctx.type == "block") return ctx.indent + (firstChar == "{" ? 0 : config.indentUnit);
152 else if (ctx.align) return ctx.column + (closing ? 0 : 1);
180 else if (ctx.flags & ALIGN_YES) return ctx.column + (closing ? 0 : 1);
153 else return ctx.indent + (closing ? 0 : config.indentUnit);
181 else return ctx.indent + (closing ? 0 : config.indentUnit);
154 },
182 },
155
183
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -28,7 +28,8 b' CodeMirror.defineMode("ruby", function(c'
28 var indentWords = wordObj(["def", "class", "case", "for", "while", "until", "module", "then",
28 var indentWords = wordObj(["def", "class", "case", "for", "while", "until", "module", "then",
29 "catch", "loop", "proc", "begin"]);
29 "catch", "loop", "proc", "begin"]);
30 var dedentWords = wordObj(["end", "until"]);
30 var dedentWords = wordObj(["end", "until"]);
31 var matching = {"[": "]", "{": "}", "(": ")"};
31 var opening = {"[": "]", "{": "}", "(": ")"};
32 var closing = {"]": "[", "}": "{", ")": "("};
32 var curPunc;
33 var curPunc;
33
34
34 function chain(newtok, stream, state) {
35 function chain(newtok, stream, state) {
@@ -46,21 +47,9 b' CodeMirror.defineMode("ruby", function(c'
46 if (ch == "`" || ch == "'" || ch == '"') {
47 if (ch == "`" || ch == "'" || ch == '"') {
47 return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state);
48 return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state);
48 } else if (ch == "/") {
49 } else if (ch == "/") {
49 var currentIndex = stream.current().length;
50 if (regexpAhead(stream))
50 if (stream.skipTo("/")) {
51 var search_till = stream.current().length;
52 stream.backUp(stream.current().length - currentIndex);
53 var balance = 0; // balance brackets
54 while (stream.current().length < search_till) {
55 var chchr = stream.next();
56 if (chchr == "(") balance += 1;
57 else if (chchr == ")") balance -= 1;
58 if (balance < 0) break;
59 }
60 stream.backUp(stream.current().length - currentIndex);
61 if (balance == 0)
62 return chain(readQuoted(ch, "string-2", true), stream, state);
51 return chain(readQuoted(ch, "string-2", true), stream, state);
63 }
52 else
64 return "operator";
53 return "operator";
65 } else if (ch == "%") {
54 } else if (ch == "%") {
66 var style = "string", embed = true;
55 var style = "string", embed = true;
@@ -70,13 +59,13 b' CodeMirror.defineMode("ruby", function(c'
70 else if (stream.eat(/[wxq]/)) { style = "string"; embed = false; }
59 else if (stream.eat(/[wxq]/)) { style = "string"; embed = false; }
71 var delim = stream.eat(/[^\w\s=]/);
60 var delim = stream.eat(/[^\w\s=]/);
72 if (!delim) return "operator";
61 if (!delim) return "operator";
73 if (matching.propertyIsEnumerable(delim)) delim = matching[delim];
62 if (opening.propertyIsEnumerable(delim)) delim = opening[delim];
74 return chain(readQuoted(delim, style, embed, true), stream, state);
63 return chain(readQuoted(delim, style, embed, true), stream, state);
75 } else if (ch == "#") {
64 } else if (ch == "#") {
76 stream.skipToEnd();
65 stream.skipToEnd();
77 return "comment";
66 return "comment";
78 } else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) {
67 } else if (ch == "<" && (m = stream.match(/^<([-~])[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) {
79 return chain(readHereDoc(m[1]), stream, state);
68 return chain(readHereDoc(m[2], m[1]), stream, state);
80 } else if (ch == "0") {
69 } else if (ch == "0") {
81 if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/);
70 if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/);
82 else if (stream.eat("b")) stream.eatWhile(/[01]/);
71 else if (stream.eat("b")) stream.eatWhile(/[01]/);
@@ -148,6 +137,28 b' CodeMirror.defineMode("ruby", function(c'
148 }
137 }
149 }
138 }
150
139
140 function regexpAhead(stream) {
141 var start = stream.pos, depth = 0, next, found = false, escaped = false
142 while ((next = stream.next()) != null) {
143 if (!escaped) {
144 if ("[{(".indexOf(next) > -1) {
145 depth++
146 } else if ("]})".indexOf(next) > -1) {
147 depth--
148 if (depth < 0) break
149 } else if (next == "/" && depth == 0) {
150 found = true
151 break
152 }
153 escaped = next == "\\"
154 } else {
155 escaped = false
156 }
157 }
158 stream.backUp(stream.pos - start)
159 return found
160 }
161
151 function tokenBaseUntilBrace(depth) {
162 function tokenBaseUntilBrace(depth) {
152 if (!depth) depth = 1;
163 if (!depth) depth = 1;
153 return function(stream, state) {
164 return function(stream, state) {
@@ -206,8 +217,9 b' CodeMirror.defineMode("ruby", function(c'
206 return style;
217 return style;
207 };
218 };
208 }
219 }
209 function readHereDoc(phrase) {
220 function readHereDoc(phrase, mayIndent) {
210 return function(stream, state) {
221 return function(stream, state) {
222 if (mayIndent) stream.eatSpace()
211 if (stream.match(phrase)) state.tokenize.pop();
223 if (stream.match(phrase)) state.tokenize.pop();
212 else stream.skipToEnd();
224 else stream.skipToEnd();
213 return "string";
225 return "string";
@@ -266,17 +278,18 b' CodeMirror.defineMode("ruby", function(c'
266 },
278 },
267
279
268 indent: function(state, textAfter) {
280 indent: function(state, textAfter) {
269 if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0;
281 if (state.tokenize[state.tokenize.length-1] != tokenBase) return CodeMirror.Pass;
270 var firstChar = textAfter && textAfter.charAt(0);
282 var firstChar = textAfter && textAfter.charAt(0);
271 var ct = state.context;
283 var ct = state.context;
272 var closing = ct.type == matching[firstChar] ||
284 var closed = ct.type == closing[firstChar] ||
273 ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter);
285 ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter);
274 return ct.indented + (closing ? 0 : config.indentUnit) +
286 return ct.indented + (closed ? 0 : config.indentUnit) +
275 (state.continuedLine ? config.indentUnit : 0);
287 (state.continuedLine ? config.indentUnit : 0);
276 },
288 },
277
289
278 electricInput: /^\s*(?:end|rescue|\})$/,
290 electricInput: /^\s*(?:end|rescue|elsif|else|\})$/,
279 lineComment: "#"
291 lineComment: "#",
292 fold: "indent"
280 };
293 };
281 });
294 });
282
295
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -68,4 +68,5 b' CodeMirror.defineSimpleMode("rust",{'
68
68
69
69
70 CodeMirror.defineMIME("text/x-rustsrc", "rust");
70 CodeMirror.defineMIME("text/x-rustsrc", "rust");
71 CodeMirror.defineMIME("text/rust", "rust");
71 });
72 });
@@ -1,17 +1,23 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
6 mod(require("../../lib/codemirror"), require("../css/css"));
7 else if (typeof define == "function" && define.amd) // AMD
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
8 define(["../../lib/codemirror", "../css/css"], mod);
9 else // Plain browser env
9 else // Plain browser env
10 mod(CodeMirror);
10 mod(CodeMirror);
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 CodeMirror.defineMode("sass", function(config) {
14 CodeMirror.defineMode("sass", function(config) {
15 var cssMode = CodeMirror.mimeModes["text/css"];
16 var propertyKeywords = cssMode.propertyKeywords || {},
17 colorKeywords = cssMode.colorKeywords || {},
18 valueKeywords = cssMode.valueKeywords || {},
19 fontProperties = cssMode.fontProperties || {};
20
15 function tokenRegexp(words) {
21 function tokenRegexp(words) {
16 return new RegExp("^" + words.join("|"));
22 return new RegExp("^" + words.join("|"));
17 }
23 }
@@ -25,6 +31,12 b' CodeMirror.defineMode("sass", function(c'
25
31
26 var pseudoElementsRegexp = /^::?[a-zA-Z_][\w\-]*/;
32 var pseudoElementsRegexp = /^::?[a-zA-Z_][\w\-]*/;
27
33
34 var word;
35
36 function isEndLine(stream) {
37 return !stream.peek() || stream.match(/\s+$/, false);
38 }
39
28 function urlTokens(stream, state) {
40 function urlTokens(stream, state) {
29 var ch = stream.peek();
41 var ch = stream.peek();
30
42
@@ -76,6 +88,9 b' CodeMirror.defineMode("sass", function(c'
76
88
77 if (endingString) {
89 if (endingString) {
78 if (nextChar !== quote && greedy) { stream.next(); }
90 if (nextChar !== quote && greedy) { stream.next(); }
91 if (isEndLine(stream)) {
92 state.cursorHalf = 0;
93 }
79 state.tokenizer = tokenBase;
94 state.tokenizer = tokenBase;
80 return "string";
95 return "string";
81 } else if (nextChar === "#" && peekChar === "{") {
96 } else if (nextChar === "#" && peekChar === "{") {
@@ -147,14 +162,20 b' CodeMirror.defineMode("sass", function(c'
147 // first half i.e. before : for key-value pairs
162 // first half i.e. before : for key-value pairs
148 // including selectors
163 // including selectors
149
164
165 if (ch === "-") {
166 if (stream.match(/^-\w+-/)) {
167 return "meta";
168 }
169 }
170
150 if (ch === ".") {
171 if (ch === ".") {
151 stream.next();
172 stream.next();
152 if (stream.match(/^[\w-]+/)) {
173 if (stream.match(/^[\w-]+/)) {
153 indent(state);
174 indent(state);
154 return "atom";
175 return "qualifier";
155 } else if (stream.peek() === "#") {
176 } else if (stream.peek() === "#") {
156 indent(state);
177 indent(state);
157 return "atom";
178 return "tag";
158 }
179 }
159 }
180 }
160
181
@@ -163,11 +184,11 b' CodeMirror.defineMode("sass", function(c'
163 // ID selectors
184 // ID selectors
164 if (stream.match(/^[\w-]+/)) {
185 if (stream.match(/^[\w-]+/)) {
165 indent(state);
186 indent(state);
166 return "atom";
187 return "builtin";
167 }
188 }
168 if (stream.peek() === "#") {
189 if (stream.peek() === "#") {
169 indent(state);
190 indent(state);
170 return "atom";
191 return "tag";
171 }
192 }
172 }
193 }
173
194
@@ -220,37 +241,48 b' CodeMirror.defineMode("sass", function(c'
220 // Indent Directives
241 // Indent Directives
221 if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) {
242 if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) {
222 indent(state);
243 indent(state);
223 return "meta";
244 return "def";
224 }
245 }
225
246
226 // Other Directives
247 // Other Directives
227 if (ch === "@") {
248 if (ch === "@") {
228 stream.next();
249 stream.next();
229 stream.eatWhile(/[\w-]/);
250 stream.eatWhile(/[\w-]/);
230 return "meta";
251 return "def";
231 }
252 }
232
253
233 if (stream.eatWhile(/[\w-]/)){
254 if (stream.eatWhile(/[\w-]/)){
234 if(stream.match(/ *: *[\w-\+\$#!\("']/,false)){
255 if(stream.match(/ *: *[\w-\+\$#!\("']/,false)){
256 word = stream.current().toLowerCase();
257 var prop = state.prevProp + "-" + word;
258 if (propertyKeywords.hasOwnProperty(prop)) {
235 return "property";
259 return "property";
260 } else if (propertyKeywords.hasOwnProperty(word)) {
261 state.prevProp = word;
262 return "property";
263 } else if (fontProperties.hasOwnProperty(word)) {
264 return "property";
265 }
266 return "tag";
236 }
267 }
237 else if(stream.match(/ *:/,false)){
268 else if(stream.match(/ *:/,false)){
238 indent(state);
269 indent(state);
239 state.cursorHalf = 1;
270 state.cursorHalf = 1;
240 return "atom";
271 state.prevProp = stream.current().toLowerCase();
272 return "property";
241 }
273 }
242 else if(stream.match(/ *,/,false)){
274 else if(stream.match(/ *,/,false)){
243 return "atom";
275 return "tag";
244 }
276 }
245 else{
277 else{
246 indent(state);
278 indent(state);
247 return "atom";
279 return "tag";
248 }
280 }
249 }
281 }
250
282
251 if(ch === ":"){
283 if(ch === ":"){
252 if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element
284 if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element
253 return "keyword";
285 return "variable-3";
254 }
286 }
255 stream.next();
287 stream.next();
256 state.cursorHalf=1;
288 state.cursorHalf=1;
@@ -264,7 +296,7 b' CodeMirror.defineMode("sass", function(c'
264 stream.next();
296 stream.next();
265 // Hex numbers
297 // Hex numbers
266 if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
298 if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
267 if(!stream.peek()){
299 if (isEndLine(stream)) {
268 state.cursorHalf = 0;
300 state.cursorHalf = 0;
269 }
301 }
270 return "number";
302 return "number";
@@ -273,7 +305,7 b' CodeMirror.defineMode("sass", function(c'
273
305
274 // Numbers
306 // Numbers
275 if (stream.match(/^-?[0-9\.]+/)){
307 if (stream.match(/^-?[0-9\.]+/)){
276 if(!stream.peek()){
308 if (isEndLine(stream)) {
277 state.cursorHalf = 0;
309 state.cursorHalf = 0;
278 }
310 }
279 return "number";
311 return "number";
@@ -281,14 +313,14 b' CodeMirror.defineMode("sass", function(c'
281
313
282 // Units
314 // Units
283 if (stream.match(/^(px|em|in)\b/)){
315 if (stream.match(/^(px|em|in)\b/)){
284 if(!stream.peek()){
316 if (isEndLine(stream)) {
285 state.cursorHalf = 0;
317 state.cursorHalf = 0;
286 }
318 }
287 return "unit";
319 return "unit";
288 }
320 }
289
321
290 if (stream.match(keywordsRegexp)){
322 if (stream.match(keywordsRegexp)){
291 if(!stream.peek()){
323 if (isEndLine(stream)) {
292 state.cursorHalf = 0;
324 state.cursorHalf = 0;
293 }
325 }
294 return "keyword";
326 return "keyword";
@@ -296,7 +328,7 b' CodeMirror.defineMode("sass", function(c'
296
328
297 if (stream.match(/^url/) && stream.peek() === "(") {
329 if (stream.match(/^url/) && stream.peek() === "(") {
298 state.tokenizer = urlTokens;
330 state.tokenizer = urlTokens;
299 if(!stream.peek()){
331 if (isEndLine(stream)) {
300 state.cursorHalf = 0;
332 state.cursorHalf = 0;
301 }
333 }
302 return "atom";
334 return "atom";
@@ -306,23 +338,21 b' CodeMirror.defineMode("sass", function(c'
306 if (ch === "$") {
338 if (ch === "$") {
307 stream.next();
339 stream.next();
308 stream.eatWhile(/[\w-]/);
340 stream.eatWhile(/[\w-]/);
309 if(!stream.peek()){
341 if (isEndLine(stream)) {
310 state.cursorHalf = 0;
342 state.cursorHalf = 0;
311 }
343 }
312 return "variable-3";
344 return "variable-2";
313 }
345 }
314
346
315 // bang character for !important, !default, etc.
347 // bang character for !important, !default, etc.
316 if (ch === "!") {
348 if (ch === "!") {
317 stream.next();
349 stream.next();
318 if(!stream.peek()){
319 state.cursorHalf = 0;
350 state.cursorHalf = 0;
320 }
321 return stream.match(/^[\w]+/) ? "keyword": "operator";
351 return stream.match(/^[\w]+/) ? "keyword": "operator";
322 }
352 }
323
353
324 if (stream.match(opRegexp)){
354 if (stream.match(opRegexp)){
325 if(!stream.peek()){
355 if (isEndLine(stream)) {
326 state.cursorHalf = 0;
356 state.cursorHalf = 0;
327 }
357 }
328 return "operator";
358 return "operator";
@@ -330,14 +360,24 b' CodeMirror.defineMode("sass", function(c'
330
360
331 // attributes
361 // attributes
332 if (stream.eatWhile(/[\w-]/)) {
362 if (stream.eatWhile(/[\w-]/)) {
333 if(!stream.peek()){
363 if (isEndLine(stream)) {
334 state.cursorHalf = 0;
364 state.cursorHalf = 0;
335 }
365 }
336 return "attribute";
366 word = stream.current().toLowerCase();
367 if (valueKeywords.hasOwnProperty(word)) {
368 return "atom";
369 } else if (colorKeywords.hasOwnProperty(word)) {
370 return "keyword";
371 } else if (propertyKeywords.hasOwnProperty(word)) {
372 state.prevProp = stream.current().toLowerCase();
373 return "property";
374 } else {
375 return "tag";
376 }
337 }
377 }
338
378
339 //stream.eatSpace();
379 //stream.eatSpace();
340 if(!stream.peek()){
380 if (isEndLine(stream)) {
341 state.cursorHalf = 0;
381 state.cursorHalf = 0;
342 return null;
382 return null;
343 }
383 }
@@ -407,7 +447,7 b' CodeMirror.defineMode("sass", function(c'
407 return state.scopes[0].offset;
447 return state.scopes[0].offset;
408 }
448 }
409 };
449 };
410 });
450 }, "css");
411
451
412 CodeMirror.defineMIME("text/x-sass", "sass");
452 CodeMirror.defineMIME("text/x-sass", "sass");
413
453
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /**
4 /**
5 * Author: Koh Zi Han, based on implementation by Koh Zi Chun
5 * Author: Koh Zi Han, based on implementation by Koh Zi Chun
@@ -73,7 +73,8 b' CodeMirror.defineMode("scheme", function'
73 indentStack: null,
73 indentStack: null,
74 indentation: 0,
74 indentation: 0,
75 mode: false,
75 mode: false,
76 sExprComment: false
76 sExprComment: false,
77 sExprQuote: false
77 };
78 };
78 },
79 },
79
80
@@ -121,7 +122,7 b' CodeMirror.defineMode("scheme", function'
121 state.sExprComment = 0;
122 state.sExprComment = 0;
122 }else{
123 }else{
123 // if not we just comment the entire of the next token
124 // if not we just comment the entire of the next token
124 stream.eatWhile(/[^/s]/); // eat non spaces
125 stream.eatWhile(/[^\s\(\)\[\]]/); // eat symbol atom
125 returnType = COMMENT;
126 returnType = COMMENT;
126 break;
127 break;
127 }
128 }
@@ -133,7 +134,15 b' CodeMirror.defineMode("scheme", function'
133 returnType = STRING;
134 returnType = STRING;
134
135
135 } else if (ch == "'") {
136 } else if (ch == "'") {
137 if (stream.peek() == "(" || stream.peek() == "["){
138 if (typeof state.sExprQuote != "number") {
139 state.sExprQuote = 0;
140 } // else already in a quoted expression
136 returnType = ATOM;
141 returnType = ATOM;
142 } else {
143 stream.eatWhile(/[\w_\-!$%&*+\.\/:<=>?@\^~]/);
144 returnType = ATOM;
145 }
137 } else if (ch == '#') {
146 } else if (ch == '#') {
138 if (stream.eat("|")) { // Multi-line comment
147 if (stream.eat("|")) { // Multi-line comment
139 state.mode = "comment"; // toggle to comment mode
148 state.mode = "comment"; // toggle to comment mode
@@ -209,6 +218,7 b' CodeMirror.defineMode("scheme", function'
209 stream.backUp(stream.current().length - 1); // undo all the eating
218 stream.backUp(stream.current().length - 1); // undo all the eating
210
219
211 if(typeof state.sExprComment == "number") state.sExprComment++;
220 if(typeof state.sExprComment == "number") state.sExprComment++;
221 if(typeof state.sExprQuote == "number") state.sExprQuote++;
212
222
213 returnType = BRACKET;
223 returnType = BRACKET;
214 } else if (ch == ")" || ch == "]") {
224 } else if (ch == ")" || ch == "]") {
@@ -222,16 +232,22 b' CodeMirror.defineMode("scheme", function'
222 state.sExprComment = false; // turn off s-expr commenting mode
232 state.sExprComment = false; // turn off s-expr commenting mode
223 }
233 }
224 }
234 }
235 if(typeof state.sExprQuote == "number"){
236 if(--state.sExprQuote == 0){
237 returnType = ATOM; // final closing bracket
238 state.sExprQuote = false; // turn off s-expr quote mode
239 }
240 }
225 }
241 }
226 } else {
242 } else {
227 stream.eatWhile(/[\w\$_\-!$%&*+\.\/:<=>?@\^~]/);
243 stream.eatWhile(/[\w_\-!$%&*+\.\/:<=>?@\^~]/);
228
244
229 if (keywords && keywords.propertyIsEnumerable(stream.current())) {
245 if (keywords && keywords.propertyIsEnumerable(stream.current())) {
230 returnType = BUILTIN;
246 returnType = BUILTIN;
231 } else returnType = "variable";
247 } else returnType = "variable";
232 }
248 }
233 }
249 }
234 return (typeof state.sExprComment == "number") ? COMMENT : returnType;
250 return (typeof state.sExprComment == "number") ? COMMENT : ((typeof state.sExprQuote == "number") ? ATOM : returnType);
235 },
251 },
236
252
237 indent: function (state) {
253 indent: function (state) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -14,26 +14,27 b''
14 CodeMirror.defineMode('shell', function() {
14 CodeMirror.defineMode('shell', function() {
15
15
16 var words = {};
16 var words = {};
17 function define(style, string) {
17 function define(style, dict) {
18 var split = string.split(' ');
18 for(var i = 0; i < dict.length; i++) {
19 for(var i = 0; i < split.length; i++) {
19 words[dict[i]] = style;
20 words[split[i]] = style;
21 }
20 }
22 };
21 };
23
22
24 // Atoms
23 var commonAtoms = ["true", "false"];
25 define('atom', 'true false');
24 var commonKeywords = ["if", "then", "do", "else", "elif", "while", "until", "for", "in", "esac", "fi",
26
25 "fin", "fil", "done", "exit", "set", "unset", "export", "function"];
27 // Keywords
26 var commonCommands = ["ab", "awk", "bash", "beep", "cat", "cc", "cd", "chown", "chmod", "chroot", "clear",
28 define('keyword', 'if then do else elif while until for in esac fi fin ' +
27 "cp", "curl", "cut", "diff", "echo", "find", "gawk", "gcc", "get", "git", "grep", "hg", "kill", "killall",
29 'fil done exit set unset export function');
28 "ln", "ls", "make", "mkdir", "openssl", "mv", "nc", "nl", "node", "npm", "ping", "ps", "restart", "rm",
29 "rmdir", "sed", "service", "sh", "shopt", "shred", "source", "sort", "sleep", "ssh", "start", "stop",
30 "su", "sudo", "svn", "tee", "telnet", "top", "touch", "vi", "vim", "wall", "wc", "wget", "who", "write",
31 "yes", "zsh"];
30
32
31 // Commands
33 CodeMirror.registerHelper("hintWords", "shell", commonAtoms.concat(commonKeywords, commonCommands));
32 define('builtin', 'ab awk bash beep cat cc cd chown chmod chroot clear cp ' +
34
33 'curl cut diff echo find gawk gcc get git grep kill killall ln ls make ' +
35 define('atom', commonAtoms);
34 'mkdir openssl mv nc node npm ping ps restart rm rmdir sed service sh ' +
36 define('keyword', commonKeywords);
35 'shopt shred source sort sleep ssh start stop su sudo tee telnet top ' +
37 define('builtin', commonCommands);
36 'touch vi vim wall wc wget who write yes zsh');
37
38
38 function tokenBase(stream, state) {
39 function tokenBase(stream, state) {
39 if (stream.eatSpace()) return null;
40 if (stream.eatSpace()) return null;
@@ -46,7 +47,7 b" CodeMirror.defineMode('shell', function("
46 return null;
47 return null;
47 }
48 }
48 if (ch === '\'' || ch === '"' || ch === '`') {
49 if (ch === '\'' || ch === '"' || ch === '`') {
49 state.tokens.unshift(tokenString(ch));
50 state.tokens.unshift(tokenString(ch, ch === "`" ? "quote" : "string"));
50 return tokenize(stream, state);
51 return tokenize(stream, state);
51 }
52 }
52 if (ch === '#') {
53 if (ch === '#') {
@@ -81,41 +82,49 b" CodeMirror.defineMode('shell', function("
81 return words.hasOwnProperty(cur) ? words[cur] : null;
82 return words.hasOwnProperty(cur) ? words[cur] : null;
82 }
83 }
83
84
84 function tokenString(quote) {
85 function tokenString(quote, style) {
86 var close = quote == "(" ? ")" : quote == "{" ? "}" : quote
85 return function(stream, state) {
87 return function(stream, state) {
86 var next, end = false, escaped = false;
88 var next, escaped = false;
87 while ((next = stream.next()) != null) {
89 while ((next = stream.next()) != null) {
88 if (next === quote && !escaped) {
90 if (next === close && !escaped) {
89 end = true;
91 state.tokens.shift();
90 break;
92 break;
91 }
93 } else if (next === '$' && !escaped && quote !== "'" && stream.peek() != close) {
92 if (next === '$' && !escaped && quote !== '\'') {
93 escaped = true;
94 escaped = true;
94 stream.backUp(1);
95 stream.backUp(1);
95 state.tokens.unshift(tokenDollar);
96 state.tokens.unshift(tokenDollar);
96 break;
97 break;
98 } else if (!escaped && quote !== close && next === quote) {
99 state.tokens.unshift(tokenString(quote, style))
100 return tokenize(stream, state)
101 } else if (!escaped && /['"]/.test(next) && !/['"]/.test(quote)) {
102 state.tokens.unshift(tokenStringStart(next, "string"));
103 stream.backUp(1);
104 break;
97 }
105 }
98 escaped = !escaped && next === '\\';
106 escaped = !escaped && next === '\\';
99 }
107 }
100 if (end || !escaped) {
108 return style;
101 state.tokens.shift();
102 }
103 return (quote === '`' || quote === ')' ? 'quote' : 'string');
104 };
109 };
105 };
110 };
106
111
112 function tokenStringStart(quote, style) {
113 return function(stream, state) {
114 state.tokens[0] = tokenString(quote, style)
115 stream.next()
116 return tokenize(stream, state)
117 }
118 }
119
107 var tokenDollar = function(stream, state) {
120 var tokenDollar = function(stream, state) {
108 if (state.tokens.length > 1) stream.eat('$');
121 if (state.tokens.length > 1) stream.eat('$');
109 var ch = stream.next(), hungry = /\w/;
122 var ch = stream.next()
110 if (ch === '{') hungry = /[^}]/;
123 if (/['"({]/.test(ch)) {
111 if (ch === '(') {
124 state.tokens[0] = tokenString(ch, ch == "(" ? "quote" : ch == "{" ? "def" : "string");
112 state.tokens[0] = tokenString(')');
113 return tokenize(stream, state);
125 return tokenize(stream, state);
114 }
126 }
115 if (!/\d/.test(ch)) {
127 if (!/\d/.test(ch)) stream.eatWhile(/\w/);
116 stream.eatWhile(hungry);
117 stream.eat('}');
118 }
119 state.tokens.shift();
128 state.tokens.shift();
120 return 'def';
129 return 'def';
121 };
130 };
@@ -129,11 +138,15 b" CodeMirror.defineMode('shell', function("
129 token: function(stream, state) {
138 token: function(stream, state) {
130 return tokenize(stream, state);
139 return tokenize(stream, state);
131 },
140 },
141 closeBrackets: "()[]{}''\"\"``",
132 lineComment: '#',
142 lineComment: '#',
133 fold: "brace"
143 fold: "brace"
134 };
144 };
135 });
145 });
136
146
137 CodeMirror.defineMIME('text/x-sh', 'shell');
147 CodeMirror.defineMIME('text/x-sh', 'shell');
148 // Apache uses a slightly different Media Type for Shell scripts
149 // http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
150 CodeMirror.defineMIME('application/x-sh', 'shell');
138
151
139 });
152 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -170,7 +170,7 b' CodeMirror.defineMode("sieve", function('
170 if (stream.eatSpace())
170 if (stream.eatSpace())
171 return null;
171 return null;
172
172
173 return (state.tokenize || tokenBase)(stream, state);;
173 return (state.tokenize || tokenBase)(stream, state);
174 },
174 },
175
175
176 indent: function(state, _textAfter) {
176 indent: function(state, _textAfter) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh
4 // Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh
5
5
@@ -165,7 +165,7 b''
165 };
165 };
166 return function(stream, state) {
166 return function(stream, state) {
167 rubyState = state.rubyState;
167 rubyState = state.rubyState;
168 state.rubyState = rubyMode.startState();
168 state.rubyState = CodeMirror.startState(rubyMode);
169 state.tokenize = runSplat;
169 state.tokenize = runSplat;
170 return ruby(stream, state);
170 return ruby(stream, state);
171 };
171 };
@@ -317,7 +317,7 b''
317
317
318 function startSubMode(mode, state) {
318 function startSubMode(mode, state) {
319 var subMode = getMode(mode);
319 var subMode = getMode(mode);
320 var subState = subMode.startState && subMode.startState();
320 var subState = CodeMirror.startState(subMode);
321
321
322 state.subMode = subMode;
322 state.subMode = subMode;
323 state.subState = subState;
323 state.subState = subState;
@@ -507,8 +507,8 b''
507 var mode = {
507 var mode = {
508 // default to html mode
508 // default to html mode
509 startState: function() {
509 startState: function() {
510 var htmlState = htmlMode.startState();
510 var htmlState = CodeMirror.startState(htmlMode);
511 var rubyState = rubyMode.startState();
511 var rubyState = CodeMirror.startState(rubyMode);
512 return {
512 return {
513 htmlState: htmlState,
513 htmlState: htmlState,
514 rubyState: rubyState,
514 rubyState: rubyState,
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /**
4 /**
5 * Smarty 2 and 3 mode.
5 * Smarty 2 and 3 mode.
@@ -210,9 +210,9 b''
210 state.last = last;
210 state.last = last;
211 return style;
211 return style;
212 },
212 },
213 indent: function(state, text) {
213 indent: function(state, text, line) {
214 if (state.tokenize == tokenTop && baseMode.indent)
214 if (state.tokenize == tokenTop && baseMode.indent)
215 return baseMode.indent(state.base, text);
215 return baseMode.indent(state.base, text, line);
216 else
216 else
217 return CodeMirror.Pass;
217 return CodeMirror.Pass;
218 },
218 },
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -14,12 +14,12 b''
14 CodeMirror.defineMode("solr", function() {
14 CodeMirror.defineMode("solr", function() {
15 "use strict";
15 "use strict";
16
16
17 var isStringChar = /[^\s\|\!\+\-\*\?\~\^\&\:\(\)\[\]\{\}\^\"\\]/;
17 var isStringChar = /[^\s\|\!\+\-\*\?\~\^\&\:\(\)\[\]\{\}\"\\]/;
18 var isOperatorChar = /[\|\!\+\-\*\?\~\^\&]/;
18 var isOperatorChar = /[\|\!\+\-\*\?\~\^\&]/;
19 var isOperatorString = /^(OR|AND|NOT|TO)$/i;
19 var isOperatorString = /^(OR|AND|NOT|TO)$/i;
20
20
21 function isNumber(word) {
21 function isNumber(word) {
22 return parseFloat(word, 10).toString() === word;
22 return parseFloat(word).toString() === word;
23 }
23 }
24
24
25 function tokenString(quote) {
25 function tokenString(quote) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -11,9 +11,45 b''
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 var indentingTags = ["template", "literal", "msg", "fallbackmsg", "let", "if", "elseif",
14 var paramData = { noEndTag: true, soyState: "param-def" };
15 "else", "switch", "case", "default", "foreach", "ifempty", "for",
15 var tags = {
16 "call", "param", "deltemplate", "delcall", "log"];
16 "alias": { noEndTag: true },
17 "delpackage": { noEndTag: true },
18 "namespace": { noEndTag: true, soyState: "namespace-def" },
19 "@param": paramData,
20 "@param?": paramData,
21 "@inject": paramData,
22 "@inject?": paramData,
23 "@state": paramData,
24 "@state?": paramData,
25 "template": { soyState: "templ-def", variableScope: true},
26 "literal": { },
27 "msg": {},
28 "fallbackmsg": { noEndTag: true, reduceIndent: true},
29 "select": {},
30 "plural": {},
31 "let": { soyState: "var-def" },
32 "if": {},
33 "elseif": { noEndTag: true, reduceIndent: true},
34 "else": { noEndTag: true, reduceIndent: true},
35 "switch": {},
36 "case": { noEndTag: true, reduceIndent: true},
37 "default": { noEndTag: true, reduceIndent: true},
38 "foreach": { variableScope: true, soyState: "var-def" },
39 "ifempty": { noEndTag: true, reduceIndent: true},
40 "for": { variableScope: true, soyState: "var-def" },
41 "call": { soyState: "templ-ref" },
42 "param": { soyState: "param-ref"},
43 "print": { noEndTag: true },
44 "deltemplate": { soyState: "templ-def", variableScope: true},
45 "delcall": { soyState: "templ-ref" },
46 "log": {},
47 "element": { variableScope: true },
48 };
49
50 var indentingTags = Object.keys(tags).filter(function(tag) {
51 return !tags[tag].noEndTag || tags[tag].reduceIndent;
52 });
17
53
18 CodeMirror.defineMode("soy", function(config) {
54 CodeMirror.defineMode("soy", function(config) {
19 var textMode = CodeMirror.getMode(config, "text/plain");
55 var textMode = CodeMirror.getMode(config, "text/plain");
@@ -22,6 +58,7 b''
22 attributes: textMode,
58 attributes: textMode,
23 text: textMode,
59 text: textMode,
24 uri: textMode,
60 uri: textMode,
61 trusted_resource_uri: textMode,
25 css: CodeMirror.getMode(config, "text/css"),
62 css: CodeMirror.getMode(config, "text/css"),
26 js: CodeMirror.getMode(config, {name: "text/javascript", statementIndent: 2 * config.indentUnit})
63 js: CodeMirror.getMode(config, {name: "text/javascript", statementIndent: 2 * config.indentUnit})
27 };
64 };
@@ -31,6 +68,12 b''
31 }
68 }
32
69
33 function tokenUntil(stream, state, untilRegExp) {
70 function tokenUntil(stream, state, untilRegExp) {
71 if (stream.sol()) {
72 for (var indent = 0; indent < state.indent; indent++) {
73 if (!stream.eat(/\s/)) break;
74 }
75 if (indent) return null;
76 }
34 var oldString = stream.string;
77 var oldString = stream.string;
35 var match = untilRegExp.exec(oldString.substr(stream.pos));
78 var match = untilRegExp.exec(oldString.substr(stream.pos));
36 if (match) {
79 if (match) {
@@ -39,33 +82,82 b''
39 stream.string = oldString.substr(0, stream.pos + match.index);
82 stream.string = oldString.substr(0, stream.pos + match.index);
40 }
83 }
41 var result = stream.hideFirstChars(state.indent, function() {
84 var result = stream.hideFirstChars(state.indent, function() {
42 return state.localMode.token(stream, state.localState);
85 var localState = last(state.localStates);
86 return localState.mode.token(stream, localState.state);
43 });
87 });
44 stream.string = oldString;
88 stream.string = oldString;
45 return result;
89 return result;
46 }
90 }
47
91
92 function contains(list, element) {
93 while (list) {
94 if (list.element === element) return true;
95 list = list.next;
96 }
97 return false;
98 }
99
100 function prepend(list, element) {
101 return {
102 element: element,
103 next: list
104 };
105 }
106
107 function popcontext(state) {
108 if (!state.context) return;
109 if (state.context.scope) {
110 state.variables = state.context.scope;
111 }
112 state.context = state.context.previousContext;
113 }
114
115 // Reference a variable `name` in `list`.
116 // Let `loose` be truthy to ignore missing identifiers.
117 function ref(list, name, loose) {
118 return contains(list, name) ? "variable-2" : (loose ? "variable" : "variable-2 error");
119 }
120
121 // Data for an open soy tag.
122 function Context(previousContext, tag, scope) {
123 this.previousContext = previousContext;
124 this.tag = tag;
125 this.kind = null;
126 this.scope = scope;
127 }
128
48 return {
129 return {
49 startState: function() {
130 startState: function() {
50 return {
131 return {
51 kind: [],
52 kindTag: [],
53 soyState: [],
132 soyState: [],
133 templates: null,
134 variables: prepend(null, 'ij'),
135 scopes: null,
54 indent: 0,
136 indent: 0,
55 localMode: modes.html,
137 quoteKind: null,
56 localState: CodeMirror.startState(modes.html)
138 context: null,
139 localStates: [{
140 mode: modes.html,
141 state: CodeMirror.startState(modes.html)
142 }]
57 };
143 };
58 },
144 },
59
145
60 copyState: function(state) {
146 copyState: function(state) {
61 return {
147 return {
62 tag: state.tag, // Last seen Soy tag.
148 tag: state.tag, // Last seen Soy tag.
63 kind: state.kind.concat([]), // Values of kind="" attributes.
64 kindTag: state.kindTag.concat([]), // Opened tags with kind="" attributes.
65 soyState: state.soyState.concat([]),
149 soyState: state.soyState.concat([]),
150 templates: state.templates,
151 variables: state.variables,
152 context: state.context,
66 indent: state.indent, // Indentation of the following line.
153 indent: state.indent, // Indentation of the following line.
67 localMode: state.localMode,
154 quoteKind: state.quoteKind,
68 localState: CodeMirror.copyState(state.localMode, state.localState)
155 localStates: state.localStates.map(function(localState) {
156 return {
157 mode: localState.mode,
158 state: CodeMirror.copyState(localState.mode, localState.state)
159 };
160 })
69 };
161 };
70 },
162 },
71
163
@@ -79,36 +171,159 b''
79 } else {
171 } else {
80 stream.skipToEnd();
172 stream.skipToEnd();
81 }
173 }
174 if (!state.context || !state.context.scope) {
175 var paramRe = /@param\??\s+(\S+)/g;
176 var current = stream.current();
177 for (var match; (match = paramRe.exec(current)); ) {
178 state.variables = prepend(state.variables, match[1]);
179 }
180 }
82 return "comment";
181 return "comment";
83
182
84 case "variable":
183 case "string":
85 if (stream.match(/^}/)) {
184 var match = stream.match(/^.*?(["']|\\[\s\S])/);
86 state.indent -= 2 * config.indentUnit;
185 if (!match) {
186 stream.skipToEnd();
187 } else if (match[1] == state.quoteKind) {
188 state.quoteKind = null;
189 state.soyState.pop();
190 }
191 return "string";
192 }
193
194 if (!state.soyState.length || last(state.soyState) != "literal") {
195 if (stream.match(/^\/\*/)) {
196 state.soyState.push("comment");
197 return "comment";
198 } else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) {
199 return "comment";
200 }
201 }
202
203 switch (last(state.soyState)) {
204 case "templ-def":
205 if (match = stream.match(/^\.?([\w]+(?!\.[\w]+)*)/)) {
206 state.templates = prepend(state.templates, match[1]);
207 state.soyState.pop();
208 return "def";
209 }
210 stream.next();
211 return null;
212
213 case "templ-ref":
214 if (match = stream.match(/(\.?[a-zA-Z_][a-zA-Z_0-9]+)+/)) {
87 state.soyState.pop();
215 state.soyState.pop();
88 return "variable-2";
216 // If the first character is '.', it can only be a local template.
217 if (match[0][0] == '.') {
218 return "variable-2"
219 }
220 // Otherwise
221 return "variable";
222 }
223 stream.next();
224 return null;
225
226 case "namespace-def":
227 if (match = stream.match(/^\.?([\w\.]+)/)) {
228 state.soyState.pop();
229 return "variable";
230 }
231 stream.next();
232 return null;
233
234 case "param-def":
235 if (match = stream.match(/^\w+/)) {
236 state.variables = prepend(state.variables, match[0]);
237 state.soyState.pop();
238 state.soyState.push("param-type");
239 return "def";
240 }
241 stream.next();
242 return null;
243
244 case "param-ref":
245 if (match = stream.match(/^\w+/)) {
246 state.soyState.pop();
247 return "property";
248 }
249 stream.next();
250 return null;
251
252 case "param-type":
253 if (stream.peek() == "}") {
254 state.soyState.pop();
255 return null;
256 }
257 if (stream.eatWhile(/^([\w]+|[?])/)) {
258 return "type";
259 }
260 stream.next();
261 return null;
262
263 case "var-def":
264 if (match = stream.match(/^\$([\w]+)/)) {
265 state.variables = prepend(state.variables, match[1]);
266 state.soyState.pop();
267 return "def";
89 }
268 }
90 stream.next();
269 stream.next();
91 return null;
270 return null;
92
271
93 case "tag":
272 case "tag":
273 var endTag = state.tag[0] == "/";
274 var tagName = endTag ? state.tag.substring(1) : state.tag;
275 var tag = tags[tagName];
94 if (stream.match(/^\/?}/)) {
276 if (stream.match(/^\/?}/)) {
95 if (state.tag == "/template" || state.tag == "/deltemplate") state.indent = 0;
277 var selfClosed = stream.current() == "/}";
96 else state.indent -= (stream.current() == "/}" || indentingTags.indexOf(state.tag) == -1 ? 2 : 1) * config.indentUnit;
278 if (selfClosed && !endTag) {
279 popcontext(state);
280 }
281 if (state.tag == "/template" || state.tag == "/deltemplate") {
282 state.variables = prepend(null, 'ij');
283 state.indent = 0;
284 } else {
285 state.indent -= config.indentUnit *
286 (selfClosed || indentingTags.indexOf(state.tag) == -1 ? 2 : 1);
287 }
97 state.soyState.pop();
288 state.soyState.pop();
98 return "keyword";
289 return "keyword";
99 } else if (stream.match(/^([\w?]+)(?==)/)) {
290 } else if (stream.match(/^([\w?]+)(?==)/)) {
100 if (stream.current() == "kind" && (match = stream.match(/^="([^"]+)/, false))) {
291 if (state.context && state.context.tag == tagName && stream.current() == "kind" && (match = stream.match(/^="([^"]+)/, false))) {
101 var kind = match[1];
292 var kind = match[1];
102 state.kind.push(kind);
293 state.context.kind = kind;
103 state.kindTag.push(state.tag);
294 var mode = modes[kind] || modes.html;
104 state.localMode = modes[kind] || modes.html;
295 var localState = last(state.localStates);
105 state.localState = CodeMirror.startState(state.localMode);
296 if (localState.mode.indent) {
297 state.indent += localState.mode.indent(localState.state, "", "");
298 }
299 state.localStates.push({
300 mode: mode,
301 state: CodeMirror.startState(mode)
302 });
106 }
303 }
107 return "attribute";
304 return "attribute";
108 } else if (stream.match(/^"/)) {
305 } else if (match = stream.match(/([\w]+)(?=\()/)) {
306 return "variable callee";
307 } else if (match = stream.match(/^["']/)) {
109 state.soyState.push("string");
308 state.soyState.push("string");
309 state.quoteKind = match;
110 return "string";
310 return "string";
111 }
311 }
312 if (stream.match(/(null|true|false)(?!\w)/) ||
313 stream.match(/0x([0-9a-fA-F]{2,})/) ||
314 stream.match(/-?([0-9]*[.])?[0-9]+(e[0-9]*)?/)) {
315 return "atom";
316 }
317 if (stream.match(/(\||[+\-*\/%]|[=!]=|\?:|[<>]=?)/)) {
318 // Tokenize filter, binary, null propagator, and equality operators.
319 return "operator";
320 }
321 if (match = stream.match(/^\$([\w]+)/)) {
322 return ref(state.variables, match[1]);
323 }
324 if (match = stream.match(/^\w+/)) {
325 return /^(?:as|and|or|not|in)$/.test(match[0]) ? "keyword" : null;
326 }
112 stream.next();
327 stream.next();
113 return null;
328 return null;
114
329
@@ -119,40 +334,59 b''
119 return this.token(stream, state);
334 return this.token(stream, state);
120 }
335 }
121 return tokenUntil(stream, state, /\{\/literal}/);
336 return tokenUntil(stream, state, /\{\/literal}/);
122
123 case "string":
124 if (stream.match(/^.*?"/)) {
125 state.soyState.pop();
126 } else {
127 stream.skipToEnd();
128 }
129 return "string";
130 }
337 }
131
338
132 if (stream.match(/^\/\*/)) {
339 if (stream.match(/^\{literal}/)) {
133 state.soyState.push("comment");
134 return "comment";
135 } else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) {
136 return "comment";
137 } else if (stream.match(/^\{\$[\w?]*/)) {
138 state.indent += 2 * config.indentUnit;
139 state.soyState.push("variable");
140 return "variable-2";
141 } else if (stream.match(/^\{literal}/)) {
142 state.indent += config.indentUnit;
340 state.indent += config.indentUnit;
143 state.soyState.push("literal");
341 state.soyState.push("literal");
342 state.context = new Context(state.context, "literal", state.variables);
144 return "keyword";
343 return "keyword";
145 } else if (match = stream.match(/^\{([\/@\\]?[\w?]*)/)) {
344
146 if (match[1] != "/switch")
345 // A tag-keyword must be followed by whitespace, comment or a closing tag.
147 state.indent += (/^(\/|(else|elseif|case|default)$)/.test(match[1]) && state.tag != "switch" ? 1 : 2) * config.indentUnit;
346 } else if (match = stream.match(/^\{([/@\\]?\w+\??)(?=$|[\s}]|\/[/*])/)) {
347 var prevTag = state.tag;
148 state.tag = match[1];
348 state.tag = match[1];
149 if (state.tag == "/" + last(state.kindTag)) {
349 var endTag = state.tag[0] == "/";
150 // We found the tag that opened the current kind="".
350 var indentingTag = !!tags[state.tag];
151 state.kind.pop();
351 var tagName = endTag ? state.tag.substring(1) : state.tag;
152 state.kindTag.pop();
352 var tag = tags[tagName];
153 state.localMode = modes[last(state.kind)] || modes.html;
353 if (state.tag != "/switch")
154 state.localState = CodeMirror.startState(state.localMode);
354 state.indent += ((endTag || tag && tag.reduceIndent) && prevTag != "switch" ? 1 : 2) * config.indentUnit;
355
356 state.soyState.push("tag");
357 var tagError = false;
358 if (tag) {
359 if (!endTag) {
360 if (tag.soyState) state.soyState.push(tag.soyState);
155 }
361 }
362 // If a new tag, open a new context.
363 if (!tag.noEndTag && (indentingTag || !endTag)) {
364 state.context = new Context(state.context, state.tag, tag.variableScope ? state.variables : null);
365 // Otherwise close the current context.
366 } else if (endTag) {
367 if (!state.context || state.context.tag != tagName) {
368 tagError = true;
369 } else if (state.context) {
370 if (state.context.kind) {
371 state.localStates.pop();
372 var localState = last(state.localStates);
373 if (localState.mode.indent) {
374 state.indent -= localState.mode.indent(localState.state, "", "");
375 }
376 }
377 popcontext(state);
378 }
379 }
380 } else if (endTag) {
381 // Assume all tags with a closing tag are defined in the config.
382 tagError = true;
383 }
384 return (tagError ? "error " : "") + "keyword";
385
386 // Not a tag-keyword; it's an implicit print tag.
387 } else if (stream.eat('{')) {
388 state.tag = "print";
389 state.indent += 2 * config.indentUnit;
156 state.soyState.push("tag");
390 state.soyState.push("tag");
157 return "keyword";
391 return "keyword";
158 }
392 }
@@ -160,7 +394,7 b''
160 return tokenUntil(stream, state, /\{|\s+\/\/|\/\*/);
394 return tokenUntil(stream, state, /\{|\s+\/\/|\/\*/);
161 },
395 },
162
396
163 indent: function(state, textAfter) {
397 indent: function(state, textAfter, line) {
164 var indent = state.indent, top = last(state.soyState);
398 var indent = state.indent, top = last(state.soyState);
165 if (top == "comment") return CodeMirror.Pass;
399 if (top == "comment") return CodeMirror.Pass;
166
400
@@ -172,14 +406,16 b''
172 if (state.tag != "switch" && /^\{(case|default)\b/.test(textAfter)) indent -= config.indentUnit;
406 if (state.tag != "switch" && /^\{(case|default)\b/.test(textAfter)) indent -= config.indentUnit;
173 if (/^\{\/switch\b/.test(textAfter)) indent -= config.indentUnit;
407 if (/^\{\/switch\b/.test(textAfter)) indent -= config.indentUnit;
174 }
408 }
175 if (indent && state.localMode.indent)
409 var localState = last(state.localStates);
176 indent += state.localMode.indent(state.localState, textAfter);
410 if (indent && localState.mode.indent) {
411 indent += localState.mode.indent(localState.state, textAfter, line);
412 }
177 return indent;
413 return indent;
178 },
414 },
179
415
180 innerMode: function(state) {
416 innerMode: function(state) {
181 if (state.soyState.length && last(state.soyState) != "literal") return null;
417 if (state.soyState.length && last(state.soyState) != "literal") return null;
182 else return {state: state.localState, mode: state.localMode};
418 else return last(state.localStates);
183 },
419 },
184
420
185 electricInput: /^\s*\{(\/|\/template|\/deltemplate|\/switch|fallbackmsg|elseif|else|case|default|ifempty|\/literal\})$/,
421 electricInput: /^\s*\{(\/|\/template|\/deltemplate|\/switch|fallbackmsg|elseif|else|case|default|ifempty|\/literal\})$/,
@@ -187,12 +423,15 b''
187 blockCommentStart: "/*",
423 blockCommentStart: "/*",
188 blockCommentEnd: "*/",
424 blockCommentEnd: "*/",
189 blockCommentContinue: " * ",
425 blockCommentContinue: " * ",
426 useInnerComments: false,
190 fold: "indent"
427 fold: "indent"
191 };
428 };
192 }, "htmlmixed");
429 }, "htmlmixed");
193
430
194 CodeMirror.registerHelper("hintWords", "soy", indentingTags.concat(
431 CodeMirror.registerHelper("wordChars", "soy", /[\w$]/);
195 ["delpackage", "namespace", "alias", "print", "css", "debugger"]));
432
433 CodeMirror.registerHelper("hintWords", "soy", Object.keys(tags).concat(
434 ["css", "debugger"]));
196
435
197 CodeMirror.defineMIME("text/x-soy", "soy");
436 CodeMirror.defineMIME("text/x-soy", "soy");
198 });
437 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -25,7 +25,7 b' CodeMirror.defineMode("sparql", function'
25 "strbefore", "strafter", "year", "month", "day", "hours", "minutes", "seconds",
25 "strbefore", "strafter", "year", "month", "day", "hours", "minutes", "seconds",
26 "timezone", "tz", "now", "uuid", "struuid", "md5", "sha1", "sha256", "sha384",
26 "timezone", "tz", "now", "uuid", "struuid", "md5", "sha1", "sha256", "sha384",
27 "sha512", "coalesce", "if", "strlang", "strdt", "isnumeric", "regex", "exists",
27 "sha512", "coalesce", "if", "strlang", "strdt", "isnumeric", "regex", "exists",
28 "isblank", "isliteral", "a"]);
28 "isblank", "isliteral", "a", "bind"]);
29 var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
29 var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
30 "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
30 "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
31 "graph", "by", "asc", "desc", "as", "having", "undef", "values", "group",
31 "graph", "by", "asc", "desc", "as", "having", "undef", "values", "group",
@@ -41,7 +41,7 b' CodeMirror.defineMode("sparql", function'
41 if(ch == "?" && stream.match(/\s/, false)){
41 if(ch == "?" && stream.match(/\s/, false)){
42 return "operator";
42 return "operator";
43 }
43 }
44 stream.match(/^[\w\d]*/);
44 stream.match(/^[A-Za-z0-9_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][A-Za-z0-9_\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*/);
45 return "variable-2";
45 return "variable-2";
46 }
46 }
47 else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) {
47 else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) {
@@ -135,7 +135,11 b' CodeMirror.defineMode("sparql", function'
135 else if (curPunc == "{") pushContext(state, "}", stream.column());
135 else if (curPunc == "{") pushContext(state, "}", stream.column());
136 else if (/[\]\}\)]/.test(curPunc)) {
136 else if (/[\]\}\)]/.test(curPunc)) {
137 while (state.context && state.context.type == "pattern") popContext(state);
137 while (state.context && state.context.type == "pattern") popContext(state);
138 if (state.context && curPunc == state.context.type) popContext(state);
138 if (state.context && curPunc == state.context.type) {
139 popContext(state);
140 if (curPunc == "}" && state.context && state.context.type == "pattern")
141 popContext(state);
142 }
139 }
143 }
140 else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state);
144 else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state);
141 else if (/atom|string|variable/.test(style) && state.context) {
145 else if (/atom|string|variable/.test(style) && state.context) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -70,7 +70,10 b''
70 return "operator";
70 return "operator";
71 case "\\":
71 case "\\":
72 if (stream.match(/\\[a-z]+/)) return "string-2";
72 if (stream.match(/\\[a-z]+/)) return "string-2";
73 else return null;
73 else {
74 stream.next();
75 return "atom";
76 }
74 case ".":
77 case ".":
75 case ",":
78 case ",":
76 case ";":
79 case ";":
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -12,16 +12,17 b''
12 "use strict";
12 "use strict";
13
13
14 CodeMirror.defineMode("sql", function(config, parserConfig) {
14 CodeMirror.defineMode("sql", function(config, parserConfig) {
15 "use strict";
16
17 var client = parserConfig.client || {},
15 var client = parserConfig.client || {},
18 atoms = parserConfig.atoms || {"false": true, "true": true, "null": true},
16 atoms = parserConfig.atoms || {"false": true, "true": true, "null": true},
19 builtin = parserConfig.builtin || {},
17 builtin = parserConfig.builtin || set(defaultBuiltin),
20 keywords = parserConfig.keywords || {},
18 keywords = parserConfig.keywords || set(sqlKeywords),
21 operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/,
19 operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^\/]/,
22 support = parserConfig.support || {},
20 support = parserConfig.support || {},
23 hooks = parserConfig.hooks || {},
21 hooks = parserConfig.hooks || {},
24 dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true};
22 dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true},
23 backslashStringEscapes = parserConfig.backslashStringEscapes !== false,
24 brackets = parserConfig.brackets || /^[\{}\(\)\[\]]/,
25 punctuation = parserConfig.punctuation || /^[;.,:]/
25
26
26 function tokenBase(stream, state) {
27 function tokenBase(stream, state) {
27 var ch = stream.next();
28 var ch = stream.next();
@@ -32,13 +33,13 b' CodeMirror.defineMode("sql", function(co'
32 if (result !== false) return result;
33 if (result !== false) return result;
33 }
34 }
34
35
35 if (support.hexNumber == true &&
36 if (support.hexNumber &&
36 ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/))
37 ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/))
37 || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) {
38 || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) {
38 // hex
39 // hex
39 // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
40 // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
40 return "number";
41 return "number";
41 } else if (support.binaryNumber == true &&
42 } else if (support.binaryNumber &&
42 (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/))
43 (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/))
43 || (ch == "0" && stream.match(/^b[01]+/)))) {
44 || (ch == "0" && stream.match(/^b[01]+/)))) {
44 // bitstring
45 // bitstring
@@ -47,8 +48,8 b' CodeMirror.defineMode("sql", function(co'
47 } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
48 } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
48 // numbers
49 // numbers
49 // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html
50 // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html
50 stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/);
51 stream.match(/^[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?/);
51 support.decimallessFloat == true && stream.eat('.');
52 support.decimallessFloat && stream.match(/^\.(?!\.)/);
52 return "number";
53 return "number";
53 } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) {
54 } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) {
54 // placeholders
55 // placeholders
@@ -58,15 +59,12 b' CodeMirror.defineMode("sql", function(co'
58 // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
59 // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
59 state.tokenize = tokenLiteral(ch);
60 state.tokenize = tokenLiteral(ch);
60 return state.tokenize(stream, state);
61 return state.tokenize(stream, state);
61 } else if ((((support.nCharCast == true && (ch == "n" || ch == "N"))
62 } else if ((((support.nCharCast && (ch == "n" || ch == "N"))
62 || (support.charsetCast == true && ch == "_" && stream.match(/[a-z][a-z0-9]*/i)))
63 || (support.charsetCast && ch == "_" && stream.match(/[a-z][a-z0-9]*/i)))
63 && (stream.peek() == "'" || stream.peek() == '"'))) {
64 && (stream.peek() == "'" || stream.peek() == '"'))) {
64 // charset casting: _utf8'str', N'str', n'str'
65 // charset casting: _utf8'str', N'str', n'str'
65 // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
66 // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
66 return "keyword";
67 return "keyword";
67 } else if (/^[\(\),\;\[\]]/.test(ch)) {
68 // no highlightning
69 return null;
70 } else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) {
68 } else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) {
71 // 1-line comment
69 // 1-line comment
72 stream.skipToEnd();
70 stream.skipToEnd();
@@ -80,22 +78,29 b' CodeMirror.defineMode("sql", function(co'
80 } else if (ch == "/" && stream.eat("*")) {
78 } else if (ch == "/" && stream.eat("*")) {
81 // multi-line comments
79 // multi-line comments
82 // ref: https://kb.askmonty.org/en/comment-syntax/
80 // ref: https://kb.askmonty.org/en/comment-syntax/
83 state.tokenize = tokenComment;
81 state.tokenize = tokenComment(1);
84 return state.tokenize(stream, state);
82 return state.tokenize(stream, state);
85 } else if (ch == ".") {
83 } else if (ch == ".") {
86 // .1 for 0.1
84 // .1 for 0.1
87 if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) {
85 if (support.zerolessFloat && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i))
88 return "number";
86 return "number";
89 }
87 if (stream.match(/^\.+/))
88 return null
90 // .table_name (ODBC)
89 // .table_name (ODBC)
91 // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
90 // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
92 if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) {
91 if (support.ODBCdotTable && stream.match(/^[\w\d_]+/))
93 return "variable-2";
92 return "variable-2";
94 }
95 } else if (operatorChars.test(ch)) {
93 } else if (operatorChars.test(ch)) {
96 // operators
94 // operators
97 stream.eatWhile(operatorChars);
95 stream.eatWhile(operatorChars);
98 return null;
96 return "operator";
97 } else if (brackets.test(ch)) {
98 // brackets
99 return "bracket";
100 } else if (punctuation.test(ch)) {
101 // punctuation
102 stream.eatWhile(punctuation);
103 return "punctuation";
99 } else if (ch == '{' &&
104 } else if (ch == '{' &&
100 (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) {
105 (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) {
101 // dates (weird ODBC syntax)
106 // dates (weird ODBC syntax)
@@ -125,25 +130,20 b' CodeMirror.defineMode("sql", function(co'
125 state.tokenize = tokenBase;
130 state.tokenize = tokenBase;
126 break;
131 break;
127 }
132 }
128 escaped = !escaped && ch == "\\";
133 escaped = backslashStringEscapes && !escaped && ch == "\\";
129 }
134 }
130 return "string";
135 return "string";
131 };
136 };
132 }
137 }
133 function tokenComment(stream, state) {
138 function tokenComment(depth) {
134 while (true) {
139 return function(stream, state) {
135 if (stream.skipTo("*")) {
140 var m = stream.match(/^.*?(\/\*|\*\/)/)
136 stream.next();
141 if (!m) stream.skipToEnd()
137 if (stream.eat("/")) {
142 else if (m[1] == "/*") state.tokenize = tokenComment(depth + 1)
138 state.tokenize = tokenBase;
143 else if (depth > 1) state.tokenize = tokenComment(depth - 1)
139 break;
144 else state.tokenize = tokenBase
145 return "comment"
140 }
146 }
141 } else {
142 stream.skipToEnd();
143 break;
144 }
145 }
146 return "comment";
147 }
147 }
148
148
149 function pushContext(stream, state, type) {
149 function pushContext(stream, state, type) {
@@ -170,7 +170,7 b' CodeMirror.defineMode("sql", function(co'
170 if (state.context && state.context.align == null)
170 if (state.context && state.context.align == null)
171 state.context.align = false;
171 state.context.align = false;
172 }
172 }
173 if (stream.eatSpace()) return null;
173 if (state.tokenize == tokenBase && stream.eatSpace()) return null;
174
174
175 var style = state.tokenize(stream, state);
175 var style = state.tokenize(stream, state);
176 if (style == "comment") return style;
176 if (style == "comment") return style;
@@ -198,13 +198,11 b' CodeMirror.defineMode("sql", function(co'
198
198
199 blockCommentStart: "/*",
199 blockCommentStart: "/*",
200 blockCommentEnd: "*/",
200 blockCommentEnd: "*/",
201 lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : null
201 lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : "--",
202 closeBrackets: "()[]{}''\"\"``"
202 };
203 };
203 });
204 });
204
205
205 (function() {
206 "use strict";
207
208 // `identifier`
206 // `identifier`
209 function hookIdentifier(stream) {
207 function hookIdentifier(stream) {
210 // MySQL/MariaDB identifiers
208 // MySQL/MariaDB identifiers
@@ -217,6 +215,19 b' CodeMirror.defineMode("sql", function(co'
217 return stream.eatWhile(/\w/) ? "variable-2" : null;
215 return stream.eatWhile(/\w/) ? "variable-2" : null;
218 }
216 }
219
217
218 // "identifier"
219 function hookIdentifierDoublequote(stream) {
220 // Standard SQL /SQLite identifiers
221 // ref: http://web.archive.org/web/20160813185132/http://savage.net.au/SQL/sql-99.bnf.html#delimited%20identifier
222 // ref: http://sqlite.org/lang_keywords.html
223 var ch;
224 while ((ch = stream.next()) != null) {
225 if (ch == "\"" && !stream.eat("\"")) return "variable-2";
226 }
227 stream.backUp(stream.current().length - 1);
228 return stream.eatWhile(/\w/) ? "variable-2" : null;
229 }
230
220 // variable token
231 // variable token
221 function hookVar(stream) {
232 function hookVar(stream) {
222 // variables
233 // variables
@@ -266,24 +277,28 b' CodeMirror.defineMode("sql", function(co'
266 return obj;
277 return obj;
267 }
278 }
268
279
280 var defaultBuiltin = "bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"
281
269 // A generic SQL Mode. It's not a standard, it just try to support what is generally supported
282 // A generic SQL Mode. It's not a standard, it just try to support what is generally supported
270 CodeMirror.defineMIME("text/x-sql", {
283 CodeMirror.defineMIME("text/x-sql", {
271 name: "sql",
284 name: "sql",
272 keywords: set(sqlKeywords + "begin"),
285 keywords: set(sqlKeywords + "begin"),
273 builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"),
286 builtin: set(defaultBuiltin),
274 atoms: set("false true null unknown"),
287 atoms: set("false true null unknown"),
275 operatorChars: /^[*+\-%<>!=]/,
276 dateSQL: set("date time timestamp"),
288 dateSQL: set("date time timestamp"),
277 support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
289 support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
278 });
290 });
279
291
280 CodeMirror.defineMIME("text/x-mssql", {
292 CodeMirror.defineMIME("text/x-mssql", {
281 name: "sql",
293 name: "sql",
282 client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
294 client: set("$partition binary_checksum checksum connectionproperty context_info current_request_id error_line error_message error_number error_procedure error_severity error_state formatmessage get_filestream_transaction_context getansinull host_id host_name isnull isnumeric min_active_rowversion newid newsequentialid rowcount_big xact_state object_id"),
283 keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare"),
295 keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare exec go if use index holdlock nolock nowait paglock readcommitted readcommittedlock readpast readuncommitted repeatableread rowlock serializable snapshot tablock tablockx updlock with"),
284 builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "),
296 builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "),
285 atoms: set("false true null unknown"),
297 atoms: set("is not null like and or in left right between inner outer join all any some cross unpivot pivot exists"),
286 operatorChars: /^[*+\-%<>!=]/,
298 operatorChars: /^[*+\-%<>!=^\&|\/]/,
299 brackets: /^[\{}\(\)]/,
300 punctuation: /^[;.,:/]/,
301 backslashStringEscapes: false,
287 dateSQL: set("date datetimeoffset datetime2 smalldatetime datetime time"),
302 dateSQL: set("date datetimeoffset datetime2 smalldatetime datetime time"),
288 hooks: {
303 hooks: {
289 "@": hookVar
304 "@": hookVar
@@ -322,6 +337,36 b' CodeMirror.defineMode("sql", function(co'
322 }
337 }
323 });
338 });
324
339
340 // provided by the phpLiteAdmin project - phpliteadmin.org
341 CodeMirror.defineMIME("text/x-sqlite", {
342 name: "sql",
343 // commands of the official SQLite client, ref: https://www.sqlite.org/cli.html#dotcmd
344 client: set("auth backup bail binary changes check clone databases dbinfo dump echo eqp exit explain fullschema headers help import imposter indexes iotrace limit lint load log mode nullvalue once open output print prompt quit read restore save scanstats schema separator session shell show stats system tables testcase timeout timer trace vfsinfo vfslist vfsname width"),
345 // ref: http://sqlite.org/lang_keywords.html
346 keywords: set(sqlKeywords + "abort action add after all analyze attach autoincrement before begin cascade case cast check collate column commit conflict constraint cross current_date current_time current_timestamp database default deferrable deferred detach each else end escape except exclusive exists explain fail for foreign full glob if ignore immediate index indexed initially inner instead intersect isnull key left limit match natural no notnull null of offset outer plan pragma primary query raise recursive references regexp reindex release rename replace restrict right rollback row savepoint temp temporary then to transaction trigger unique using vacuum view virtual when with without"),
347 // SQLite is weakly typed, ref: http://sqlite.org/datatype3.html. This is just a list of some common types.
348 builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text clob bigint int int2 int8 integer float double char varchar date datetime year unsigned signed numeric real"),
349 // ref: http://sqlite.org/syntax/literal-value.html
350 atoms: set("null current_date current_time current_timestamp"),
351 // ref: http://sqlite.org/lang_expr.html#binaryops
352 operatorChars: /^[*+\-%<>!=&|/~]/,
353 // SQLite is weakly typed, ref: http://sqlite.org/datatype3.html. This is just a list of some common types.
354 dateSQL: set("date time timestamp datetime"),
355 support: set("decimallessFloat zerolessFloat"),
356 identifierQuote: "\"", //ref: http://sqlite.org/lang_keywords.html
357 hooks: {
358 // bind-parameters ref:http://sqlite.org/lang_expr.html#varparam
359 "@": hookVar,
360 ":": hookVar,
361 "?": hookVar,
362 "$": hookVar,
363 // The preferred way to escape Identifiers is using double quotes, ref: http://sqlite.org/lang_keywords.html
364 "\"": hookIdentifierDoublequote,
365 // there is also support for backtics, ref: http://sqlite.org/lang_keywords.html
366 "`": hookIdentifier
367 }
368 });
369
325 // the query language used by Apache Cassandra is called CQL, but this mime type
370 // the query language used by Apache Cassandra is called CQL, but this mime type
326 // is called Cassandra to avoid confusion with Contextual Query Language
371 // is called Cassandra to avoid confusion with Contextual Query Language
327 CodeMirror.defineMIME("text/x-cassandra", {
372 CodeMirror.defineMIME("text/x-cassandra", {
@@ -341,8 +386,8 b' CodeMirror.defineMode("sql", function(co'
341 name: "sql",
386 name: "sql",
342 client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"),
387 client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"),
343 keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"),
388 keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"),
344 builtin: set("abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml"),
389 builtin: set("abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least length lengthb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml"),
345 operatorChars: /^[*+\-%<>!=~]/,
390 operatorChars: /^[*\/+\-%<>!=~]/,
346 dateSQL: set("date time timestamp"),
391 dateSQL: set("date time timestamp"),
347 support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber")
392 support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber")
348 });
393 });
@@ -350,15 +395,73 b' CodeMirror.defineMode("sql", function(co'
350 // Created to support specific hive keywords
395 // Created to support specific hive keywords
351 CodeMirror.defineMIME("text/x-hive", {
396 CodeMirror.defineMIME("text/x-hive", {
352 name: "sql",
397 name: "sql",
353 keywords: set("select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external false fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger true unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with"),
398 keywords: set("select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with admin authorization char compact compactions conf cube current current_date current_timestamp day decimal defined dependency directories elem_type exchange file following for grouping hour ignore inner interval jar less logical macro minute month more none noscan over owner partialscan preceding pretty principals protection reload rewrite role roles rollup rows second server sets skewed transactions truncate unbounded unset uri user values window year"),
354 builtin: set("bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype"),
399 builtin: set("bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype key_type utctimestamp value_type varchar"),
355 atoms: set("false true null unknown"),
400 atoms: set("false true null unknown"),
356 operatorChars: /^[*+\-%<>!=]/,
401 operatorChars: /^[*+\-%<>!=]/,
357 dateSQL: set("date timestamp"),
402 dateSQL: set("date timestamp"),
358 support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
403 support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
359 });
404 });
360 }());
405
406 CodeMirror.defineMIME("text/x-pgsql", {
407 name: "sql",
408 client: set("source"),
409 // For PostgreSQL - https://www.postgresql.org/docs/11/sql-keywords-appendix.html
410 // For pl/pgsql lang - https://github.com/postgres/postgres/blob/REL_11_2/src/pl/plpgsql/src/pl_scanner.c
411 keywords: set(sqlKeywords + "a abort abs absent absolute access according action ada add admin after aggregate alias all allocate also alter always analyse analyze and any are array array_agg array_max_cardinality as asc asensitive assert assertion assignment asymmetric at atomic attach attribute attributes authorization avg backward base64 before begin begin_frame begin_partition bernoulli between bigint binary bit bit_length blob blocked bom boolean both breadth by c cache call called cardinality cascade cascaded case cast catalog catalog_name ceil ceiling chain char char_length character character_length character_set_catalog character_set_name character_set_schema characteristics characters check checkpoint class class_origin clob close cluster coalesce cobol collate collation collation_catalog collation_name collation_schema collect column column_name columns command_function command_function_code comment comments commit committed concurrently condition condition_number configuration conflict connect connection connection_name constant constraint constraint_catalog constraint_name constraint_schema constraints constructor contains content continue control conversion convert copy corr corresponding cost count covar_pop covar_samp create cross csv cube cume_dist current current_catalog current_date current_default_transform_group current_path current_role current_row current_schema current_time current_timestamp current_transform_group_for_type current_user cursor cursor_name cycle data database datalink datatype date datetime_interval_code datetime_interval_precision day db deallocate debug dec decimal declare default defaults deferrable deferred defined definer degree delete delimiter delimiters dense_rank depends depth deref derived desc describe descriptor detach detail deterministic diagnostics dictionary disable discard disconnect dispatch distinct dlnewcopy dlpreviouscopy dlurlcomplete dlurlcompleteonly dlurlcompletewrite dlurlpath dlurlpathonly dlurlpathwrite dlurlscheme dlurlserver dlvalue do document domain double drop dump dynamic dynamic_function dynamic_function_code each element else elseif elsif empty enable encoding encrypted end end_frame end_partition endexec enforced enum equals errcode error escape event every except exception exclude excluding exclusive exec execute exists exit exp explain expression extension external extract false family fetch file filter final first first_value flag float floor following for force foreach foreign fortran forward found frame_row free freeze from fs full function functions fusion g general generated get global go goto grant granted greatest group grouping groups handler having header hex hierarchy hint hold hour id identity if ignore ilike immediate immediately immutable implementation implicit import in include including increment indent index indexes indicator info inherit inherits initially inline inner inout input insensitive insert instance instantiable instead int integer integrity intersect intersection interval into invoker is isnull isolation join k key key_member key_type label lag language large last last_value lateral lead leading leakproof least left length level library like like_regex limit link listen ln load local localtime localtimestamp location locator lock locked log logged loop lower m map mapping match matched materialized max max_cardinality maxvalue member merge message message_length message_octet_length message_text method min minute minvalue mod mode modifies module month more move multiset mumps name names namespace national natural nchar nclob nesting new next nfc nfd nfkc nfkd nil no none normalize normalized not nothing notice notify notnull nowait nth_value ntile null nullable nullif nulls number numeric object occurrences_regex octet_length octets of off offset oids old on only open operator option options or order ordering ordinality others out outer output over overlaps overlay overriding owned owner p pad parallel parameter parameter_mode parameter_name parameter_ordinal_position parameter_specific_catalog parameter_specific_name parameter_specific_schema parser partial partition pascal passing passthrough password path percent percent_rank percentile_cont percentile_disc perform period permission pg_context pg_datatype_name pg_exception_context pg_exception_detail pg_exception_hint placing plans pli policy portion position position_regex power precedes preceding precision prepare prepared preserve primary print_strict_params prior privileges procedural procedure procedures program public publication query quote raise range rank read reads real reassign recheck recovery recursive ref references referencing refresh regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy regr_syy reindex relative release rename repeatable replace replica requiring reset respect restart restore restrict result result_oid return returned_cardinality returned_length returned_octet_length returned_sqlstate returning returns reverse revoke right role rollback rollup routine routine_catalog routine_name routine_schema routines row row_count row_number rows rowtype rule savepoint scale schema schema_name schemas scope scope_catalog scope_name scope_schema scroll search second section security select selective self sensitive sequence sequences serializable server server_name session session_user set setof sets share show similar simple size skip slice smallint snapshot some source space specific specific_name specifictype sql sqlcode sqlerror sqlexception sqlstate sqlwarning sqrt stable stacked standalone start state statement static statistics stddev_pop stddev_samp stdin stdout storage strict strip structure style subclass_origin submultiset subscription substring substring_regex succeeds sum symmetric sysid system system_time system_user t table table_name tables tablesample tablespace temp template temporary text then ties time timestamp timezone_hour timezone_minute to token top_level_count trailing transaction transaction_active transactions_committed transactions_rolled_back transform transforms translate translate_regex translation treat trigger trigger_catalog trigger_name trigger_schema trim trim_array true truncate trusted type types uescape unbounded uncommitted under unencrypted union unique unknown unlink unlisten unlogged unnamed unnest until untyped update upper uri usage use_column use_variable user user_defined_type_catalog user_defined_type_code user_defined_type_name user_defined_type_schema using vacuum valid validate validator value value_of values var_pop var_samp varbinary varchar variable_conflict variadic varying verbose version versioning view views volatile warning when whenever where while whitespace width_bucket window with within without work wrapper write xml xmlagg xmlattributes xmlbinary xmlcast xmlcomment xmlconcat xmldeclaration xmldocument xmlelement xmlexists xmlforest xmliterate xmlnamespaces xmlparse xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltext xmlvalidate year yes zone"),
412 // https://www.postgresql.org/docs/11/datatype.html
413 builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"),
414 atoms: set("false true null unknown"),
415 operatorChars: /^[*\/+\-%<>!=&|^\/#@?~]/,
416 dateSQL: set("date time timestamp"),
417 support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast")
418 });
419
420 // Google's SQL-like query language, GQL
421 CodeMirror.defineMIME("text/x-gql", {
422 name: "sql",
423 keywords: set("ancestor and asc by contains desc descendant distinct from group has in is limit offset on order select superset where"),
424 atoms: set("false true"),
425 builtin: set("blob datetime first key __key__ string integer double boolean null"),
426 operatorChars: /^[*+\-%<>!=]/
427 });
361
428
429 // Greenplum
430 CodeMirror.defineMIME("text/x-gpsql", {
431 name: "sql",
432 client: set("source"),
433 //https://github.com/greenplum-db/gpdb/blob/master/src/include/parser/kwlist.h
434 keywords: set("abort absolute access action active add admin after aggregate all also alter always analyse analyze and any array as asc assertion assignment asymmetric at authorization backward before begin between bigint binary bit boolean both by cache called cascade cascaded case cast chain char character characteristics check checkpoint class close cluster coalesce codegen collate column comment commit committed concurrency concurrently configuration connection constraint constraints contains content continue conversion copy cost cpu_rate_limit create createdb createexttable createrole createuser cross csv cube current current_catalog current_date current_role current_schema current_time current_timestamp current_user cursor cycle data database day deallocate dec decimal declare decode default defaults deferrable deferred definer delete delimiter delimiters deny desc dictionary disable discard distinct distributed do document domain double drop dxl each else enable encoding encrypted end enum errors escape every except exchange exclude excluding exclusive execute exists explain extension external extract false family fetch fields filespace fill filter first float following for force foreign format forward freeze from full function global grant granted greatest group group_id grouping handler hash having header hold host hour identity if ignore ilike immediate immutable implicit in including inclusive increment index indexes inherit inherits initially inline inner inout input insensitive insert instead int integer intersect interval into invoker is isnull isolation join key language large last leading least left level like limit list listen load local localtime localtimestamp location lock log login mapping master match maxvalue median merge minute minvalue missing mode modifies modify month move name names national natural nchar new newline next no nocreatedb nocreateexttable nocreaterole nocreateuser noinherit nologin none noovercommit nosuperuser not nothing notify notnull nowait null nullif nulls numeric object of off offset oids old on only operator option options or order ordered others out outer over overcommit overlaps overlay owned owner parser partial partition partitions passing password percent percentile_cont percentile_disc placing plans position preceding precision prepare prepared preserve primary prior privileges procedural procedure protocol queue quote randomly range read readable reads real reassign recheck recursive ref references reindex reject relative release rename repeatable replace replica reset resource restart restrict returning returns revoke right role rollback rollup rootpartition row rows rule savepoint scatter schema scroll search second security segment select sequence serializable session session_user set setof sets share show similar simple smallint some split sql stable standalone start statement statistics stdin stdout storage strict strip subpartition subpartitions substring superuser symmetric sysid system table tablespace temp template temporary text then threshold ties time timestamp to trailing transaction treat trigger trim true truncate trusted type unbounded uncommitted unencrypted union unique unknown unlisten until update user using vacuum valid validation validator value values varchar variadic varying verbose version view volatile web when where whitespace window with within without work writable write xml xmlattributes xmlconcat xmlelement xmlexists xmlforest xmlparse xmlpi xmlroot xmlserialize year yes zone"),
435 builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"),
436 atoms: set("false true null unknown"),
437 operatorChars: /^[*+\-%<>!=&|^\/#@?~]/,
438 dateSQL: set("date time timestamp"),
439 support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast")
440 });
441
442 // Spark SQL
443 CodeMirror.defineMIME("text/x-sparksql", {
444 name: "sql",
445 keywords: set("add after all alter analyze and anti archive array as asc at between bucket buckets by cache cascade case cast change clear cluster clustered codegen collection column columns comment commit compact compactions compute concatenate cost create cross cube current current_date current_timestamp database databases datata dbproperties defined delete delimited deny desc describe dfs directories distinct distribute drop else end escaped except exchange exists explain export extended external false fields fileformat first following for format formatted from full function functions global grant group grouping having if ignore import in index indexes inner inpath inputformat insert intersect interval into is items join keys last lateral lazy left like limit lines list load local location lock locks logical macro map minus msck natural no not null nulls of on optimize option options or order out outer outputformat over overwrite partition partitioned partitions percent preceding principals purge range recordreader recordwriter recover reduce refresh regexp rename repair replace reset restrict revoke right rlike role roles rollback rollup row rows schema schemas select semi separated serde serdeproperties set sets show skewed sort sorted start statistics stored stratify struct table tables tablesample tblproperties temp temporary terminated then to touch transaction transactions transform true truncate unarchive unbounded uncache union unlock unset use using values view when where window with"),
446 builtin: set("tinyint smallint int bigint boolean float double string binary timestamp decimal array map struct uniontype delimited serde sequencefile textfile rcfile inputformat outputformat"),
447 atoms: set("false true null"),
448 operatorChars: /^[*\/+\-%<>!=~&|^]/,
449 dateSQL: set("date time timestamp"),
450 support: set("ODBCdotTable doubleQuote zerolessFloat")
451 });
452
453 // Esper
454 CodeMirror.defineMIME("text/x-esper", {
455 name: "sql",
456 client: set("source"),
457 // http://www.espertech.com/esper/release-5.5.0/esper-reference/html/appendix_keywords.html
458 keywords: set("alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit after all and as at asc avedev avg between by case cast coalesce count create current_timestamp day days delete define desc distinct else end escape events every exists false first from full group having hour hours in inner insert instanceof into irstream is istream join last lastweekday left limit like max match_recognize matches median measures metadatasql min minute minutes msec millisecond milliseconds not null offset on or order outer output partition pattern prev prior regexp retain-union retain-intersection right rstream sec second seconds select set some snapshot sql stddev sum then true unidirectional until update variable weekday when where window"),
459 builtin: {},
460 atoms: set("false true null"),
461 operatorChars: /^[*+\-%<>!=&|^\/#@?~]/,
462 dateSQL: set("time"),
463 support: set("decimallessFloat zerolessFloat binaryNumber hexNumber")
464 });
362 });
465 });
363
466
364 /*
467 /*
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /*
4 /*
5 * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)
5 * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)
@@ -16,7 +16,7 b''
16 })(function(CodeMirror) {
16 })(function(CodeMirror) {
17 "use strict";
17 "use strict";
18
18
19 CodeMirror.defineMode("stex", function() {
19 CodeMirror.defineMode("stex", function(_config, parserConfig) {
20 "use strict";
20 "use strict";
21
21
22 function pushCommand(state, command) {
22 function pushCommand(state, command) {
@@ -78,6 +78,14 b''
78 plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]);
78 plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]);
79 plugins["end"] = addPluginPattern("end", "tag", ["atom"]);
79 plugins["end"] = addPluginPattern("end", "tag", ["atom"]);
80
80
81 plugins["label" ] = addPluginPattern("label" , "tag", ["atom"]);
82 plugins["ref" ] = addPluginPattern("ref" , "tag", ["atom"]);
83 plugins["eqref" ] = addPluginPattern("eqref" , "tag", ["atom"]);
84 plugins["cite" ] = addPluginPattern("cite" , "tag", ["atom"]);
85 plugins["bibitem" ] = addPluginPattern("bibitem" , "tag", ["atom"]);
86 plugins["Bibitem" ] = addPluginPattern("Bibitem" , "tag", ["atom"]);
87 plugins["RBibitem" ] = addPluginPattern("RBibitem" , "tag", ["atom"]);
88
81 plugins["DEFAULT"] = function () {
89 plugins["DEFAULT"] = function () {
82 this.name = "DEFAULT";
90 this.name = "DEFAULT";
83 this.style = "tag";
91 this.style = "tag";
@@ -117,6 +125,10 b''
117 setState(state, function(source, state){ return inMathMode(source, state, "\\]"); });
125 setState(state, function(source, state){ return inMathMode(source, state, "\\]"); });
118 return "keyword";
126 return "keyword";
119 }
127 }
128 if (source.match("\\(")) {
129 setState(state, function(source, state){ return inMathMode(source, state, "\\)"); });
130 return "keyword";
131 }
120 if (source.match("$$")) {
132 if (source.match("$$")) {
121 setState(state, function(source, state){ return inMathMode(source, state, "$$"); });
133 setState(state, function(source, state){ return inMathMode(source, state, "$$"); });
122 return "keyword";
134 return "keyword";
@@ -161,7 +173,7 b''
161 if (source.eatSpace()) {
173 if (source.eatSpace()) {
162 return null;
174 return null;
163 }
175 }
164 if (source.match(endModeSeq)) {
176 if (endModeSeq && source.match(endModeSeq)) {
165 setState(state, normal);
177 setState(state, normal);
166 return "keyword";
178 return "keyword";
167 }
179 }
@@ -223,9 +235,10 b''
223
235
224 return {
236 return {
225 startState: function() {
237 startState: function() {
238 var f = parserConfig.inMathMode ? function(source, state){ return inMathMode(source, state); } : normal;
226 return {
239 return {
227 cmdState: [],
240 cmdState: [],
228 f: normal
241 f: f
229 };
242 };
230 },
243 },
231 copyState: function(s) {
244 copyState: function(s) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Stylus mode created by Dmitry Kiselyov http://git.io/AaRB
4 // Stylus mode created by Dmitry Kiselyov http://git.io/AaRB
5
5
@@ -15,6 +15,7 b''
15
15
16 CodeMirror.defineMode("stylus", function(config) {
16 CodeMirror.defineMode("stylus", function(config) {
17 var indentUnit = config.indentUnit,
17 var indentUnit = config.indentUnit,
18 indentUnitString = '',
18 tagKeywords = keySet(tagKeywords_),
19 tagKeywords = keySet(tagKeywords_),
19 tagVariablesRegexp = /^(a|b|i|s|col|em)$/i,
20 tagVariablesRegexp = /^(a|b|i|s|col|em)$/i,
20 propertyKeywords = keySet(propertyKeywords_),
21 propertyKeywords = keySet(propertyKeywords_),
@@ -38,6 +39,8 b''
38 type,
39 type,
39 override;
40 override;
40
41
42 while (indentUnitString.length < indentUnit) indentUnitString += ' ';
43
41 /**
44 /**
42 * Tokenizers
45 * Tokenizers
43 */
46 */
@@ -73,7 +76,7 b''
73 if (ch == "#") {
76 if (ch == "#") {
74 stream.next();
77 stream.next();
75 // Hex color
78 // Hex color
76 if (stream.match(/^[0-9a-f]{6}|[0-9a-f]{3}/i)) {
79 if (stream.match(/^[0-9a-f]{3}([0-9a-f]([0-9a-f]{2}){0,2})?\b/i)) {
77 return ["atom", "atom"];
80 return ["atom", "atom"];
78 }
81 }
79 // ID selector
82 // ID selector
@@ -313,7 +316,7 b''
313 return pushContext(state, stream, "block", 0);
316 return pushContext(state, stream, "block", 0);
314 }
317 }
315 }
318 }
316 if (typeIsBlock(type, stream, state)) {
319 if (typeIsBlock(type, stream)) {
317 return pushContext(state, stream, "block");
320 return pushContext(state, stream, "block");
318 }
321 }
319 if (type == "}" && endOfLine(stream)) {
322 if (type == "}" && endOfLine(stream)) {
@@ -513,7 +516,7 b''
513 */
516 */
514 states.atBlock = function(type, stream, state) {
517 states.atBlock = function(type, stream, state) {
515 if (type == "(") return pushContext(state, stream, "atBlock_parens");
518 if (type == "(") return pushContext(state, stream, "atBlock_parens");
516 if (typeIsBlock(type, stream, state)) {
519 if (typeIsBlock(type, stream)) {
517 return pushContext(state, stream, "block");
520 return pushContext(state, stream, "block");
518 }
521 }
519 if (typeIsInterpolation(type, stream)) {
522 if (typeIsInterpolation(type, stream)) {
@@ -672,7 +675,7 b''
672 ch = textAfter && textAfter.charAt(0),
675 ch = textAfter && textAfter.charAt(0),
673 indent = cx.indent,
676 indent = cx.indent,
674 lineFirstWord = firstWordOfLine(textAfter),
677 lineFirstWord = firstWordOfLine(textAfter),
675 lineIndent = line.length - line.replace(/^\s*/, "").length,
678 lineIndent = line.match(/^\s*/)[0].replace(/\t/g, indentUnitString).length,
676 prevLineFirstWord = state.context.prev ? state.context.prev.line.firstWord : "",
679 prevLineFirstWord = state.context.prev ? state.context.prev.line.firstWord : "",
677 prevLineIndent = state.context.prev ? state.context.prev.line.indent : lineIndent;
680 prevLineIndent = state.context.prev ? state.context.prev.line.indent : lineIndent;
678
681
@@ -681,7 +684,6 b''
681 ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
684 ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
682 ch == "{" && (cx.type == "at"))) {
685 ch == "{" && (cx.type == "at"))) {
683 indent = cx.indent - indentUnit;
686 indent = cx.indent - indentUnit;
684 cx = cx.prev;
685 } else if (!(/(\})/.test(ch))) {
687 } else if (!(/(\})/.test(ch))) {
686 if (/@|\$|\d/.test(ch) ||
688 if (/@|\$|\d/.test(ch) ||
687 /^\{/.test(textAfter) ||
689 /^\{/.test(textAfter) ||
@@ -732,11 +734,11 b''
732 var documentTypes_ = ["domain", "regexp", "url", "url-prefix"];
734 var documentTypes_ = ["domain", "regexp", "url", "url-prefix"];
733 var mediaTypes_ = ["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"];
735 var mediaTypes_ = ["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"];
734 var mediaFeatures_ = ["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid"];
736 var mediaFeatures_ = ["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid"];
735 var propertyKeywords_ = ["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-position","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode","font-smoothing","osx-font-smoothing"];
737 var propertyKeywords_ = ["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-position","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode","font-smoothing","osx-font-smoothing"];
736 var nonStandardPropertyKeywords_ = ["scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-3d-light-color","scrollbar-track-color","shape-inside","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","zoom"];
738 var nonStandardPropertyKeywords_ = ["scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-3d-light-color","scrollbar-track-color","shape-inside","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","zoom"];
737 var fontProperties_ = ["font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"];
739 var fontProperties_ = ["font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"];
738 var colorKeywords_ = ["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"];
740 var colorKeywords_ = ["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"];
739 var valueKeywords_ = ["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","bullets","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","compact","condensed","contain","content","content-box","context-menu","continuous","copy","counter","counters","cover","crop","cross","crosshair","currentcolor","cursive","cyclic","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","flex","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","matrix","matrix3d","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row-resize","rtl","run-in","running","s-resize","sans-serif","scale","scale3d","scaleX","scaleY","scaleZ","scroll","scrollbar","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","spell-out","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","symbolic","symbols","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","x-large","x-small","xor","xx-large","xx-small","bicubic","optimizespeed","grayscale","row","row-reverse","wrap","wrap-reverse","column-reverse","flex-start","flex-end","space-between","space-around"];
741 var valueKeywords_ = ["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","bullets","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","compact","condensed","contain","content","contents","content-box","context-menu","continuous","copy","counter","counters","cover","crop","cross","crosshair","currentcolor","cursive","cyclic","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","flex","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","matrix","matrix3d","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row-resize","rtl","run-in","running","s-resize","sans-serif","scale","scale3d","scaleX","scaleY","scaleZ","scroll","scrollbar","scroll-position","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","spell-out","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","symbolic","symbols","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","x-large","x-small","xor","xx-large","xx-small","bicubic","optimizespeed","grayscale","row","row-reverse","wrap","wrap-reverse","column-reverse","flex-start","flex-end","space-between","space-around", "unset"];
740
742
741 var wordOperatorKeywords_ = ["in","and","or","not","is not","is a","is","isnt","defined","if unless"],
743 var wordOperatorKeywords_ = ["in","and","or","not","is not","is a","is","isnt","defined","if unless"],
742 blockKeywords_ = ["for","if","else","unless", "from", "to"],
744 blockKeywords_ = ["for","if","else","unless", "from", "to"],
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Swift mode created by Michael Kaminsky https://github.com/mkaminsky11
4 // Swift mode created by Michael Kaminsky https://github.com/mkaminsky11
5
5
@@ -19,25 +19,28 b''
19 return set
19 return set
20 }
20 }
21
21
22 var keywords = wordSet(["var","let","class","deinit","enum","extension","func","import","init","protocol",
22 var keywords = wordSet(["_","var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype",
23 "static","struct","subscript","typealias","as","dynamicType","is","new","super",
23 "open","public","internal","fileprivate","private","deinit","init","new","override","self","subscript","super",
24 "self","Self","Type","__COLUMN__","__FILE__","__FUNCTION__","__LINE__","break","case",
24 "convenience","dynamic","final","indirect","lazy","required","static","unowned","unowned(safe)","unowned(unsafe)","weak","as","is",
25 "continue","default","do","else","fallthrough","if","in","for","return","switch",
25 "break","case","continue","default","else","fallthrough","for","guard","if","in","repeat","switch","where","while",
26 "where","while","associativity","didSet","get","infix","inout","left","mutating",
26 "defer","return","inout","mutating","nonmutating","catch","do","rethrows","throw","throws","try","didSet","get","set","willSet",
27 "none","nonmutating","operator","override","postfix","precedence","prefix","right",
27 "assignment","associativity","infix","left","none","operator","postfix","precedence","precedencegroup","prefix","right",
28 "set","unowned","weak","willSet"])
28 "Any","AnyObject","Type","dynamicType","Self","Protocol","__COLUMN__","__FILE__","__FUNCTION__","__LINE__"])
29 var definingKeywords = wordSet(["var","let","class","enum","extension","func","import","protocol","struct",
29 var definingKeywords = wordSet(["var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype","for"])
30 "typealias","dynamicType","for"])
30 var atoms = wordSet(["true","false","nil","self","super","_"])
31 var atoms = wordSet(["Infinity","NaN","undefined","null","true","false","on","off","yes","no","nil","null",
31 var types = wordSet(["Array","Bool","Character","Dictionary","Double","Float","Int","Int8","Int16","Int32","Int64","Never","Optional","Set","String",
32 "this","super"])
32 "UInt8","UInt16","UInt32","UInt64","Void"])
33 var types = wordSet(["String","bool","int","string","double","Double","Int","Float","float","public",
33 var operators = "+-/*%=|&<>~^?!"
34 "private","extension"])
34 var punc = ":;,.(){}[]"
35 var operators = "+-/*%=|&<>#"
35 var binary = /^\-?0b[01][01_]*/
36 var punc = ";,.(){}[]"
36 var octal = /^\-?0o[0-7][0-7_]*/
37 var number = /^-?(?:(?:[\d_]+\.[_\d]*|\.[_\d]+|0o[0-7_\.]+|0b[01_\.]+)(?:e-?[\d_]+)?|0x[\d_a-f\.]+(?:p-?[\d_]+)?)/i
37 var hexadecimal = /^\-?0x[\dA-Fa-f][\dA-Fa-f_]*(?:(?:\.[\dA-Fa-f][\dA-Fa-f_]*)?[Pp]\-?\d[\d_]*)?/
38 var identifier = /^[_A-Za-z$][_A-Za-z$0-9]*/
38 var decimal = /^\-?\d[\d_]*(?:\.\d[\d_]*)?(?:[Ee]\-?\d[\d_]*)?/
39 var property = /^[@\.][_A-Za-z$][_A-Za-z$0-9]*/
39 var identifier = /^\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1/
40 var regexp = /^\/(?!\s)(?:\/\/)?(?:\\.|[^\/])+\//
40 var property = /^\.(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/
41 var instruction = /^\#[A-Za-z]+/
42 var attribute = /^@(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/
43 //var regexp = /^\/(?!\s)(?:\/\/)?(?:\\.|[^\/])+\//
41
44
42 function tokenBase(stream, state, prev) {
45 function tokenBase(stream, state, prev) {
43 if (stream.sol()) state.indented = stream.indentation()
46 if (stream.sol()) state.indented = stream.indentation()
@@ -53,8 +56,14 b''
53 state.tokenize.push(tokenComment)
56 state.tokenize.push(tokenComment)
54 return tokenComment(stream, state)
57 return tokenComment(stream, state)
55 }
58 }
56 if (stream.match(regexp)) return "string-2"
57 }
59 }
60 if (stream.match(instruction)) return "builtin"
61 if (stream.match(attribute)) return "attribute"
62 if (stream.match(binary)) return "number"
63 if (stream.match(octal)) return "number"
64 if (stream.match(hexadecimal)) return "number"
65 if (stream.match(decimal)) return "number"
66 if (stream.match(property)) return "property"
58 if (operators.indexOf(ch) > -1) {
67 if (operators.indexOf(ch) > -1) {
59 stream.next()
68 stream.next()
60 return "operator"
69 return "operator"
@@ -64,25 +73,22 b''
64 stream.match("..")
73 stream.match("..")
65 return "punctuation"
74 return "punctuation"
66 }
75 }
67 if (ch == '"' || ch == "'") {
76 var stringMatch
68 stream.next()
77 if (stringMatch = stream.match(/("""|"|')/)) {
69 var tokenize = tokenString(ch)
78 var tokenize = tokenString.bind(null, stringMatch[0])
70 state.tokenize.push(tokenize)
79 state.tokenize.push(tokenize)
71 return tokenize(stream, state)
80 return tokenize(stream, state)
72 }
81 }
73
82
74 if (stream.match(number)) return "number"
75 if (stream.match(property)) return "property"
76
77 if (stream.match(identifier)) {
83 if (stream.match(identifier)) {
78 var ident = stream.current()
84 var ident = stream.current()
85 if (types.hasOwnProperty(ident)) return "variable-2"
86 if (atoms.hasOwnProperty(ident)) return "atom"
79 if (keywords.hasOwnProperty(ident)) {
87 if (keywords.hasOwnProperty(ident)) {
80 if (definingKeywords.hasOwnProperty(ident))
88 if (definingKeywords.hasOwnProperty(ident))
81 state.prev = "define"
89 state.prev = "define"
82 return "keyword"
90 return "keyword"
83 }
91 }
84 if (types.hasOwnProperty(ident)) return "variable-2"
85 if (atoms.hasOwnProperty(ident)) return "atom"
86 if (prev == "define") return "def"
92 if (prev == "define") return "def"
87 return "variable"
93 return "variable"
88 }
94 }
@@ -110,30 +116,43 b''
110 }
116 }
111 }
117 }
112
118
113 function tokenString(quote) {
119 function tokenString(openQuote, stream, state) {
114 return function(stream, state) {
120 var singleLine = openQuote.length == 1
115 var ch, escaped = false
121 var ch, escaped = false
116 while (ch = stream.next()) {
122 while (ch = stream.peek()) {
117 if (escaped) {
123 if (escaped) {
124 stream.next()
118 if (ch == "(") {
125 if (ch == "(") {
119 state.tokenize.push(tokenUntilClosingParen())
126 state.tokenize.push(tokenUntilClosingParen())
120 return "string"
127 return "string"
121 }
128 }
122 escaped = false
129 escaped = false
123 } else if (ch == quote) {
130 } else if (stream.match(openQuote)) {
124 break
131 state.tokenize.pop()
132 return "string"
125 } else {
133 } else {
134 stream.next()
126 escaped = ch == "\\"
135 escaped = ch == "\\"
127 }
136 }
128 }
137 }
138 if (singleLine) {
129 state.tokenize.pop()
139 state.tokenize.pop()
140 }
130 return "string"
141 return "string"
131 }
142 }
132 }
133
143
134 function tokenComment(stream, state) {
144 function tokenComment(stream, state) {
135 stream.match(/^(?:[^*]|\*(?!\/))*/)
145 var ch
136 if (stream.match("*/")) state.tokenize.pop()
146 while (true) {
147 stream.match(/^[^/*]+/, true)
148 ch = stream.next()
149 if (!ch) break
150 if (ch === "/" && stream.eat("*")) {
151 state.tokenize.push(tokenComment)
152 } else if (ch === "*" && stream.eat("/")) {
153 state.tokenize.pop()
154 }
155 }
137 return "comment"
156 return "comment"
138 }
157 }
139
158
@@ -194,9 +213,11 b''
194
213
195 lineComment: "//",
214 lineComment: "//",
196 blockCommentStart: "/*",
215 blockCommentStart: "/*",
197 blockCommentEnd: "*/"
216 blockCommentEnd: "*/",
217 fold: "brace",
218 closeBrackets: "()[]{}''\"\"``"
198 }
219 }
199 })
220 })
200
221
201 CodeMirror.defineMIME("text/x-swift","swift")
222 CodeMirror.defineMIME("text/x-swift","swift")
202 })
223 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 //tcl mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara
4 //tcl mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara
5
5
@@ -42,42 +42,34 b' CodeMirror.defineMode("tcl", function() '
42 var beforeParams = state.beforeParams;
42 var beforeParams = state.beforeParams;
43 state.beforeParams = false;
43 state.beforeParams = false;
44 var ch = stream.next();
44 var ch = stream.next();
45 if ((ch == '"' || ch == "'") && state.inParams)
45 if ((ch == '"' || ch == "'") && state.inParams) {
46 return chain(stream, state, tokenString(ch));
46 return chain(stream, state, tokenString(ch));
47 else if (/[\[\]{}\(\),;\.]/.test(ch)) {
47 } else if (/[\[\]{}\(\),;\.]/.test(ch)) {
48 if (ch == "(" && beforeParams) state.inParams = true;
48 if (ch == "(" && beforeParams) state.inParams = true;
49 else if (ch == ")") state.inParams = false;
49 else if (ch == ")") state.inParams = false;
50 return null;
50 return null;
51 }
51 } else if (/\d/.test(ch)) {
52 else if (/\d/.test(ch)) {
53 stream.eatWhile(/[\w\.]/);
52 stream.eatWhile(/[\w\.]/);
54 return "number";
53 return "number";
55 }
54 } else if (ch == "#") {
56 else if (ch == "#" && stream.eat("*")) {
55 if (stream.eat("*"))
57 return chain(stream, state, tokenComment);
56 return chain(stream, state, tokenComment);
58 }
57 if (ch == "#" && stream.match(/ *\[ *\[/))
59 else if (ch == "#" && stream.match(/ *\[ *\[/)) {
60 return chain(stream, state, tokenUnparsed);
58 return chain(stream, state, tokenUnparsed);
61 }
62 else if (ch == "#" && stream.eat("#")) {
63 stream.skipToEnd();
59 stream.skipToEnd();
64 return "comment";
60 return "comment";
65 }
61 } else if (ch == '"') {
66 else if (ch == '"') {
67 stream.skipTo(/"/);
62 stream.skipTo(/"/);
68 return "comment";
63 return "comment";
69 }
64 } else if (ch == "$") {
70 else if (ch == "$") {
71 stream.eatWhile(/[$_a-z0-9A-Z\.{:]/);
65 stream.eatWhile(/[$_a-z0-9A-Z\.{:]/);
72 stream.eatWhile(/}/);
66 stream.eatWhile(/}/);
73 state.beforeParams = true;
67 state.beforeParams = true;
74 return "builtin";
68 return "builtin";
75 }
69 } else if (isOperatorChar.test(ch)) {
76 else if (isOperatorChar.test(ch)) {
77 stream.eatWhile(isOperatorChar);
70 stream.eatWhile(isOperatorChar);
78 return "comment";
71 return "comment";
79 }
72 } else {
80 else {
81 stream.eatWhile(/[\w\$_{}\xa1-\uffff]/);
73 stream.eatWhile(/[\w\$_{}\xa1-\uffff]/);
82 var word = stream.current().toLowerCase();
74 var word = stream.current().toLowerCase();
83 if (keywords && keywords.propertyIsEnumerable(word))
75 if (keywords && keywords.propertyIsEnumerable(word))
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") { // CommonJS
5 if (typeof exports == "object" && typeof module == "object") { // CommonJS
@@ -203,7 +203,7 b''
203 single: {
203 single: {
204 bc: "bc",
204 bc: "bc",
205 bq: "bq",
205 bq: "bq",
206 definitionList: /- [^(?::=)]+:=+/,
206 definitionList: /- .*?:=+/,
207 definitionListEnd: /.*=:\s*$/,
207 definitionListEnd: /.*=:\s*$/,
208 div: "div",
208 div: "div",
209 drawTable: /\|.*\|/,
209 drawTable: /\|.*\|/,
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /***
4 /***
5 |''Name''|tiddlywiki.js|
5 |''Name''|tiddlywiki.js|
@@ -8,7 +8,7 b''
8 |''Version''|0.1.7|
8 |''Version''|0.1.7|
9 |''Status''|''stable''|
9 |''Status''|''stable''|
10 |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]|
10 |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]|
11 |''Documentation''|http://codemirror.tiddlyspace.com/|
11 |''Documentation''|https://codemirror.tiddlyspace.com/|
12 |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]|
12 |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]|
13 |''CoreVersion''|2.5.0|
13 |''CoreVersion''|2.5.0|
14 |''Requires''|codemirror.js|
14 |''Requires''|codemirror.js|
@@ -16,7 +16,6 b''
16 ! Info
16 ! Info
17 CoreVersion parameter is needed for TiddlyWiki only!
17 CoreVersion parameter is needed for TiddlyWiki only!
18 ***/
18 ***/
19 //{{{
20
19
21 (function(mod) {
20 (function(mod) {
22 if (typeof exports == "object" && typeof module == "object") // CommonJS
21 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -32,23 +31,16 b' CodeMirror.defineMode("tiddlywiki", func'
32 // Tokenizer
31 // Tokenizer
33 var textwords = {};
32 var textwords = {};
34
33
35 var keywords = function () {
34 var keywords = {
36 function kw(type) {
35 "allTags": true, "closeAll": true, "list": true,
37 return { type: type, style: "macro"};
36 "newJournal": true, "newTiddler": true,
38 }
37 "permaview": true, "saveChanges": true,
39 return {
38 "search": true, "slider": true, "tabs": true,
40 "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'),
39 "tag": true, "tagging": true, "tags": true,
41 "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'),
40 "tiddler": true, "timeline": true,
42 "permaview": kw('permaview'), "saveChanges": kw('saveChanges'),
41 "today": true, "version": true, "option": true,
43 "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'),
42 "with": true, "filter": true
44 "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'),
45 "tiddler": kw('tiddler'), "timeline": kw('timeline'),
46 "today": kw('today'), "version": kw('version'), "option": kw('option'),
47
48 "with": kw('with'),
49 "filter": kw('filter')
50 };
43 };
51 }();
52
44
53 var isSpaceName = /[\w_\-]/i,
45 var isSpaceName = /[\w_\-]/i,
54 reHR = /^\-\-\-\-+$/, // <hr>
46 reHR = /^\-\-\-\-+$/, // <hr>
@@ -71,34 +63,28 b' CodeMirror.defineMode("tiddlywiki", func'
71 return f(stream, state);
63 return f(stream, state);
72 }
64 }
73
65
74 function jsTokenBase(stream, state) {
66 function tokenBase(stream, state) {
75 var sol = stream.sol(), ch;
67 var sol = stream.sol(), ch = stream.peek();
76
68
77 state.block = false; // indicates the start of a code block.
69 state.block = false; // indicates the start of a code block.
78
70
79 ch = stream.peek(); // don't eat, to make matching simpler
80
81 // check start of blocks
71 // check start of blocks
82 if (sol && /[<\/\*{}\-]/.test(ch)) {
72 if (sol && /[<\/\*{}\-]/.test(ch)) {
83 if (stream.match(reCodeBlockStart)) {
73 if (stream.match(reCodeBlockStart)) {
84 state.block = true;
74 state.block = true;
85 return chain(stream, state, twTokenCode);
75 return chain(stream, state, twTokenCode);
86 }
76 }
87 if (stream.match(reBlockQuote)) {
77 if (stream.match(reBlockQuote))
88 return 'quote';
78 return 'quote';
89 }
79 if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop))
90 if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) {
91 return 'comment';
80 return 'comment';
92 }
81 if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop))
93 if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) {
94 return 'comment';
82 return 'comment';
95 }
83 if (stream.match(reHR))
96 if (stream.match(reHR)) {
97 return 'hr';
84 return 'hr';
98 }
85 }
99 } // sol
100 ch = stream.next();
101
86
87 stream.next();
102 if (sol && /[\/\*!#;:>|]/.test(ch)) {
88 if (sol && /[\/\*!#;:>|]/.test(ch)) {
103 if (ch == "!") { // tw header
89 if (ch == "!") { // tw header
104 stream.skipToEnd();
90 stream.skipToEnd();
@@ -124,58 +110,52 b' CodeMirror.defineMode("tiddlywiki", func'
124 stream.eatWhile(">");
110 stream.eatWhile(">");
125 return "quote";
111 return "quote";
126 }
112 }
127 if (ch == '|') {
113 if (ch == '|')
128 return 'header';
114 return 'header';
129 }
115 }
130 }
131
116
132 if (ch == '{' && stream.match(/\{\{/)) {
117 if (ch == '{' && stream.match(/\{\{/))
133 return chain(stream, state, twTokenCode);
118 return chain(stream, state, twTokenCode);
134 }
135
119
136 // rudimentary html:// file:// link matching. TW knows much more ...
120 // rudimentary html:// file:// link matching. TW knows much more ...
137 if (/[hf]/i.test(ch)) {
121 if (/[hf]/i.test(ch) &&
138 if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) {
122 /[ti]/i.test(stream.peek()) &&
123 stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i))
139 return "link";
124 return "link";
140 }
125
141 }
142 // just a little string indicator, don't want to have the whole string covered
126 // just a little string indicator, don't want to have the whole string covered
143 if (ch == '"') {
127 if (ch == '"')
144 return 'string';
128 return 'string';
145 }
129
146 if (ch == '~') { // _no_ CamelCase indicator should be bold
130 if (ch == '~') // _no_ CamelCase indicator should be bold
147 return 'brace';
131 return 'brace';
148 }
132
149 if (/[\[\]]/.test(ch)) { // check for [[..]]
133 if (/[\[\]]/.test(ch) && stream.match(ch)) // check for [[..]]
150 if (stream.peek() == ch) {
151 stream.next();
152 return 'brace';
134 return 'brace';
153 }
135
154 }
155 if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting
136 if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting
156 stream.eatWhile(isSpaceName);
137 stream.eatWhile(isSpaceName);
157 return "link";
138 return "link";
158 }
139 }
140
159 if (/\d/.test(ch)) { // numbers
141 if (/\d/.test(ch)) { // numbers
160 stream.eatWhile(/\d/);
142 stream.eatWhile(/\d/);
161 return "number";
143 return "number";
162 }
144 }
145
163 if (ch == "/") { // tw invisible comment
146 if (ch == "/") { // tw invisible comment
164 if (stream.eat("%")) {
147 if (stream.eat("%")) {
165 return chain(stream, state, twTokenComment);
148 return chain(stream, state, twTokenComment);
166 }
149 } else if (stream.eat("/")) { //
167 else if (stream.eat("/")) { //
168 return chain(stream, state, twTokenEm);
150 return chain(stream, state, twTokenEm);
169 }
151 }
170 }
152 }
171 if (ch == "_") { // tw underline
153
172 if (stream.eat("_")) {
154 if (ch == "_" && stream.eat("_")) // tw underline
173 return chain(stream, state, twTokenUnderline);
155 return chain(stream, state, twTokenUnderline);
174 }
156
175 }
176 // strikethrough and mdash handling
157 // strikethrough and mdash handling
177 if (ch == "-") {
158 if (ch == "-" && stream.eat("-")) {
178 if (stream.eat("-")) {
179 // if strikethrough looks ugly, change CSS.
159 // if strikethrough looks ugly, change CSS.
180 if (stream.peek() != ' ')
160 if (stream.peek() != ' ')
181 return chain(stream, state, twTokenStrike);
161 return chain(stream, state, twTokenStrike);
@@ -183,36 +163,24 b' CodeMirror.defineMode("tiddlywiki", func'
183 if (stream.peek() == ' ')
163 if (stream.peek() == ' ')
184 return 'brace';
164 return 'brace';
185 }
165 }
186 }
166
187 if (ch == "'") { // tw bold
167 if (ch == "'" && stream.eat("'")) // tw bold
188 if (stream.eat("'")) {
189 return chain(stream, state, twTokenStrong);
168 return chain(stream, state, twTokenStrong);
190 }
169
191 }
170 if (ch == "<" && stream.eat("<")) // tw macro
192 if (ch == "<") { // tw macro
193 if (stream.eat("<")) {
194 return chain(stream, state, twTokenMacro);
171 return chain(stream, state, twTokenMacro);
195 }
196 }
197 else {
198 return null;
199 }
200
172
201 // core macro handling
173 // core macro handling
202 stream.eatWhile(/[\w\$_]/);
174 stream.eatWhile(/[\w\$_]/);
203 var word = stream.current(),
175 return textwords.propertyIsEnumerable(stream.current()) ? "keyword" : null
204 known = textwords.propertyIsEnumerable(word) && textwords[word];
176 }
205
206 return known ? known.style : null;
207 } // jsTokenBase()
208
177
209 // tw invisible comment
178 // tw invisible comment
210 function twTokenComment(stream, state) {
179 function twTokenComment(stream, state) {
211 var maybeEnd = false,
180 var maybeEnd = false, ch;
212 ch;
213 while (ch = stream.next()) {
181 while (ch = stream.next()) {
214 if (ch == "/" && maybeEnd) {
182 if (ch == "/" && maybeEnd) {
215 state.tokenize = jsTokenBase;
183 state.tokenize = tokenBase;
216 break;
184 break;
217 }
185 }
218 maybeEnd = (ch == "%");
186 maybeEnd = (ch == "%");
@@ -226,7 +194,7 b' CodeMirror.defineMode("tiddlywiki", func'
226 ch;
194 ch;
227 while (ch = stream.next()) {
195 while (ch = stream.next()) {
228 if (ch == "'" && maybeEnd) {
196 if (ch == "'" && maybeEnd) {
229 state.tokenize = jsTokenBase;
197 state.tokenize = tokenBase;
230 break;
198 break;
231 }
199 }
232 maybeEnd = (ch == "'");
200 maybeEnd = (ch == "'");
@@ -243,12 +211,12 b' CodeMirror.defineMode("tiddlywiki", func'
243 }
211 }
244
212
245 if (!sb && stream.match(reUntilCodeStop)) {
213 if (!sb && stream.match(reUntilCodeStop)) {
246 state.tokenize = jsTokenBase;
214 state.tokenize = tokenBase;
247 return "comment";
215 return "comment";
248 }
216 }
249
217
250 if (sb && stream.sol() && stream.match(reCodeBlockStop)) {
218 if (sb && stream.sol() && stream.match(reCodeBlockStop)) {
251 state.tokenize = jsTokenBase;
219 state.tokenize = tokenBase;
252 return "comment";
220 return "comment";
253 }
221 }
254
222
@@ -262,7 +230,7 b' CodeMirror.defineMode("tiddlywiki", func'
262 ch;
230 ch;
263 while (ch = stream.next()) {
231 while (ch = stream.next()) {
264 if (ch == "/" && maybeEnd) {
232 if (ch == "/" && maybeEnd) {
265 state.tokenize = jsTokenBase;
233 state.tokenize = tokenBase;
266 break;
234 break;
267 }
235 }
268 maybeEnd = (ch == "/");
236 maybeEnd = (ch == "/");
@@ -276,7 +244,7 b' CodeMirror.defineMode("tiddlywiki", func'
276 ch;
244 ch;
277 while (ch = stream.next()) {
245 while (ch = stream.next()) {
278 if (ch == "_" && maybeEnd) {
246 if (ch == "_" && maybeEnd) {
279 state.tokenize = jsTokenBase;
247 state.tokenize = tokenBase;
280 break;
248 break;
281 }
249 }
282 maybeEnd = (ch == "_");
250 maybeEnd = (ch == "_");
@@ -291,7 +259,7 b' CodeMirror.defineMode("tiddlywiki", func'
291
259
292 while (ch = stream.next()) {
260 while (ch = stream.next()) {
293 if (ch == "-" && maybeEnd) {
261 if (ch == "-" && maybeEnd) {
294 state.tokenize = jsTokenBase;
262 state.tokenize = tokenBase;
295 break;
263 break;
296 }
264 }
297 maybeEnd = (ch == "-");
265 maybeEnd = (ch == "-");
@@ -301,58 +269,40 b' CodeMirror.defineMode("tiddlywiki", func'
301
269
302 // macro
270 // macro
303 function twTokenMacro(stream, state) {
271 function twTokenMacro(stream, state) {
304 var ch, word, known;
305
306 if (stream.current() == '<<') {
272 if (stream.current() == '<<') {
307 return 'macro';
273 return 'macro';
308 }
274 }
309
275
310 ch = stream.next();
276 var ch = stream.next();
311 if (!ch) {
277 if (!ch) {
312 state.tokenize = jsTokenBase;
278 state.tokenize = tokenBase;
313 return null;
279 return null;
314 }
280 }
315 if (ch == ">") {
281 if (ch == ">") {
316 if (stream.peek() == '>') {
282 if (stream.peek() == '>') {
317 stream.next();
283 stream.next();
318 state.tokenize = jsTokenBase;
284 state.tokenize = tokenBase;
319 return "macro";
285 return "macro";
320 }
286 }
321 }
287 }
322
288
323 stream.eatWhile(/[\w\$_]/);
289 stream.eatWhile(/[\w\$_]/);
324 word = stream.current();
290 return keywords.propertyIsEnumerable(stream.current()) ? "keyword" : null
325 known = keywords.propertyIsEnumerable(word) && keywords[word];
326
327 if (known) {
328 return known.style, word;
329 }
330 else {
331 return null, word;
332 }
333 }
291 }
334
292
335 // Interface
293 // Interface
336 return {
294 return {
337 startState: function () {
295 startState: function () {
338 return {
296 return {tokenize: tokenBase};
339 tokenize: jsTokenBase,
340 indented: 0,
341 level: 0
342 };
343 },
297 },
344
298
345 token: function (stream, state) {
299 token: function (stream, state) {
346 if (stream.eatSpace()) return null;
300 if (stream.eatSpace()) return null;
347 var style = state.tokenize(stream, state);
301 var style = state.tokenize(stream, state);
348 return style;
302 return style;
349 },
303 }
350
351 electricChars: ""
352 };
304 };
353 });
305 });
354
306
355 CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki");
307 CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki");
356 });
308 });
357
358 //}}}
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -144,7 +144,7 b" CodeMirror.defineMode('tiki', function(c"
144 type = "equals";
144 type = "equals";
145
145
146 if (peek == ">") {
146 if (peek == ">") {
147 ch = stream.next();
147 stream.next();
148 peek = stream.peek();
148 peek = stream.peek();
149 }
149 }
150
150
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object")
5 if (typeof exports == "object" && typeof module == "object")
@@ -77,6 +77,8 b" CodeMirror.defineMode('troff', function("
77 };
77 };
78 });
78 });
79
79
80 CodeMirror.defineMIME('troff', 'troff');
80 CodeMirror.defineMIME('text/troff', 'troff');
81 CodeMirror.defineMIME('text/x-troff', 'troff');
82 CodeMirror.defineMIME('application/x-troff', 'troff');
81
83
82 });
84 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,17 +1,17 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
6 mod(require("../../lib/codemirror"), require("../../addon/mode/multiplex"));
7 else if (typeof define == "function" && define.amd) // AMD
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
8 define(["../../lib/codemirror", "../../addon/mode/multiplex"], mod);
9 else // Plain browser env
9 else // Plain browser env
10 mod(CodeMirror);
10 mod(CodeMirror);
11 })(function(CodeMirror) {
11 })(function(CodeMirror) {
12 "use strict";
12 "use strict";
13
13
14 CodeMirror.defineMode("twig", function() {
14 CodeMirror.defineMode("twig:inner", function() {
15 var keywords = ["and", "as", "autoescape", "endautoescape", "block", "do", "endblock", "else", "elseif", "extends", "for", "endfor", "embed", "endembed", "filter", "endfilter", "flush", "from", "if", "endif", "in", "is", "include", "import", "not", "or", "set", "spaceless", "endspaceless", "with", "endwith", "trans", "endtrans", "blocktrans", "endblocktrans", "macro", "endmacro", "use", "verbatim", "endverbatim"],
15 var keywords = ["and", "as", "autoescape", "endautoescape", "block", "do", "endblock", "else", "elseif", "extends", "for", "endfor", "embed", "endembed", "filter", "endfilter", "flush", "from", "if", "endif", "in", "is", "include", "import", "not", "or", "set", "spaceless", "endspaceless", "with", "endwith", "trans", "endtrans", "blocktrans", "endblocktrans", "macro", "endmacro", "use", "verbatim", "endverbatim"],
16 operator = /^[+\-*&%=<>!?|~^]/,
16 operator = /^[+\-*&%=<>!?|~^]/,
17 sign = /^[:\[\(\{]/,
17 sign = /^[:\[\(\{]/,
@@ -95,7 +95,7 b''
95 }
95 }
96 return "variable";
96 return "variable";
97 } else if (stream.eat("{")) {
97 } else if (stream.eat("{")) {
98 if (ch = stream.eat("#")) {
98 if (stream.eat("#")) {
99 state.incomment = true;
99 state.incomment = true;
100 if (!stream.skipTo("#}")) {
100 if (!stream.skipTo("#}")) {
101 stream.skipToEnd();
101 stream.skipToEnd();
@@ -128,5 +128,14 b''
128 };
128 };
129 });
129 });
130
130
131 CodeMirror.defineMode("twig", function(config, parserConfig) {
132 var twigInner = CodeMirror.getMode(config, "twig:inner");
133 if (!parserConfig || !parserConfig.base) return twigInner;
134 return CodeMirror.multiplexingMode(
135 CodeMirror.getMode(config, parserConfig.base), {
136 open: /\{[{#%]/, close: /[}#%]\}/, mode: twigInner, parseDelimiters: true
137 }
138 );
139 });
131 CodeMirror.defineMIME("text/x-twig", "twig");
140 CodeMirror.defineMIME("text/x-twig", "twig");
132 });
141 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -25,16 +25,16 b' CodeMirror.defineMode("vb", function(con'
25 var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
25 var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
26 var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
26 var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
27
27
28 var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property', 'try'];
28 var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property', 'try', 'structure', 'synclock', 'using', 'with'];
29 var middleKeywords = ['else','elseif','case', 'catch'];
29 var middleKeywords = ['else','elseif','case', 'catch', 'finally'];
30 var endKeywords = ['next','loop'];
30 var endKeywords = ['next','loop'];
31
31
32 var operatorKeywords = ['and', 'or', 'not', 'xor', 'in'];
32 var operatorKeywords = ['and', "andalso", 'or', 'orelse', 'xor', 'in', 'not', 'is', 'isnot', 'like'];
33 var wordOperators = wordRegexp(operatorKeywords);
33 var wordOperators = wordRegexp(operatorKeywords);
34 var commonKeywords = ['as', 'dim', 'break', 'continue','optional', 'then', 'until',
34
35 'goto', 'byval','byref','new','handles','property', 'return',
35 var commonKeywords = ["#const", "#else", "#elseif", "#end", "#if", "#region", "addhandler", "addressof", "alias", "as", "byref", "byval", "cbool", "cbyte", "cchar", "cdate", "cdbl", "cdec", "cint", "clng", "cobj", "compare", "const", "continue", "csbyte", "cshort", "csng", "cstr", "cuint", "culng", "cushort", "declare", "default", "delegate", "dim", "directcast", "each", "erase", "error", "event", "exit", "explicit", "false", "for", "friend", "gettype", "goto", "handles", "implements", "imports", "infer", "inherits", "interface", "isfalse", "istrue", "lib", "me", "mod", "mustinherit", "mustoverride", "my", "mybase", "myclass", "namespace", "narrowing", "new", "nothing", "notinheritable", "notoverridable", "of", "off", "on", "operator", "option", "optional", "out", "overloads", "overridable", "overrides", "paramarray", "partial", "private", "protected", "public", "raiseevent", "readonly", "redim", "removehandler", "resume", "return", "shadows", "shared", "static", "step", "stop", "strict", "then", "throw", "to", "true", "trycast", "typeof", "until", "until", "when", "widening", "withevents", "writeonly"];
36 'const','private', 'protected', 'friend', 'public', 'shared', 'static', 'true','false'];
36
37 var commontypes = ['integer','string','double','decimal','boolean','short','char', 'float','single'];
37 var commontypes = ['object', 'boolean', 'char', 'string', 'byte', 'sbyte', 'short', 'ushort', 'int16', 'uint16', 'integer', 'uinteger', 'int32', 'uint32', 'long', 'ulong', 'int64', 'uint64', 'decimal', 'single', 'double', 'float', 'date', 'datetime', 'intptr', 'uintptr'];
38
38
39 var keywords = wordRegexp(commonKeywords);
39 var keywords = wordRegexp(commonKeywords);
40 var types = wordRegexp(commontypes);
40 var types = wordRegexp(commontypes);
@@ -202,7 +202,6 b' CodeMirror.defineMode("vb", function(con'
202 // Handle '.' connected identifiers
202 // Handle '.' connected identifiers
203 if (current === '.') {
203 if (current === '.') {
204 style = state.tokenize(stream, state);
204 style = state.tokenize(stream, state);
205 current = stream.current();
206 if (style === 'variable') {
205 if (style === 'variable') {
207 return 'variable';
206 return 'variable';
208 } else {
207 } else {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 /*
4 /*
5 For extra ASP classic objects, initialize CodeMirror instance with this option:
5 For extra ASP classic objects, initialize CodeMirror instance with this option:
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -34,7 +34,7 b' CodeMirror.defineMode("velocity", functi'
34 state.beforeParams = false;
34 state.beforeParams = false;
35 var ch = stream.next();
35 var ch = stream.next();
36 // start of unparsed string?
36 // start of unparsed string?
37 if ((ch == "'") && state.inParams) {
37 if ((ch == "'") && !state.inString && state.inParams) {
38 state.lastTokenWasBuiltin = false;
38 state.lastTokenWasBuiltin = false;
39 return chain(stream, state, tokenString(ch));
39 return chain(stream, state, tokenString(ch));
40 }
40 }
@@ -82,7 +82,7 b' CodeMirror.defineMode("velocity", functi'
82 }
82 }
83 // variable?
83 // variable?
84 else if (ch == "$") {
84 else if (ch == "$") {
85 stream.eatWhile(/[\w\d\$_\.{}]/);
85 stream.eatWhile(/[\w\d\$_\.{}-]/);
86 // is it one of the specials?
86 // is it one of the specials?
87 if (specials && specials.propertyIsEnumerable(stream.current())) {
87 if (specials && specials.propertyIsEnumerable(stream.current())) {
88 return "keyword";
88 return "keyword";
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -250,7 +250,7 b' CodeMirror.defineMode("verilog", functio'
250 if (text == contextClosing) {
250 if (text == contextClosing) {
251 return true;
251 return true;
252 } else {
252 } else {
253 // contextClosing may be mulitple keywords separated by ;
253 // contextClosing may be multiple keywords separated by ;
254 var closingKeywords = contextClosing.split(";");
254 var closingKeywords = contextClosing.split(";");
255 for (var i in closingKeywords) {
255 for (var i in closingKeywords) {
256 if (text == closingKeywords[i]) {
256 if (text == closingKeywords[i]) {
@@ -302,7 +302,13 b' CodeMirror.defineMode("verilog", functio'
302 state.indented = stream.indentation();
302 state.indented = stream.indentation();
303 state.startOfLine = true;
303 state.startOfLine = true;
304 }
304 }
305 if (hooks.token) hooks.token(stream, state);
305 if (hooks.token) {
306 // Call hook, with an optional return value of a style to override verilog styling.
307 var style = hooks.token(stream, state);
308 if (style !== undefined) {
309 return style;
310 }
311 }
306 if (stream.eatSpace()) return null;
312 if (stream.eatSpace()) return null;
307 curPunc = null;
313 curPunc = null;
308 curKeyword = null;
314 curKeyword = null;
@@ -375,163 +381,295 b' CodeMirror.defineMode("verilog", functio'
375 name: "verilog"
381 name: "verilog"
376 });
382 });
377
383
378 // TLVVerilog mode
384
385
386 // TL-Verilog mode.
387 // See tl-x.org for language spec.
388 // See the mode in action at makerchip.com.
389 // Contact: steve.hoover@redwoodeda.com
379
390
380 var tlvchScopePrefixes = {
391 // TLV Identifier prefixes.
381 ">": "property", "->": "property", "-": "hr", "|": "link", "?$": "qualifier", "?*": "qualifier",
392 // Note that sign is not treated separately, so "+/-" versions of numeric identifiers
382 "@-": "variable-3", "@": "variable-3", "?": "qualifier"
393 // are included.
394 var tlvIdentifierStyle = {
395 "|": "link",
396 ">": "property", // Should condition this off for > TLV 1c.
397 "$": "variable",
398 "$$": "variable",
399 "?$": "qualifier",
400 "?*": "qualifier",
401 "-": "hr",
402 "/": "property",
403 "/-": "property",
404 "@": "variable-3",
405 "@-": "variable-3",
406 "@++": "variable-3",
407 "@+=": "variable-3",
408 "@+=-": "variable-3",
409 "@--": "variable-3",
410 "@-=": "variable-3",
411 "%+": "tag",
412 "%-": "tag",
413 "%": "tag",
414 ">>": "tag",
415 "<<": "tag",
416 "<>": "tag",
417 "#": "tag", // Need to choose a style for this.
418 "^": "attribute",
419 "^^": "attribute",
420 "^!": "attribute",
421 "*": "variable-2",
422 "**": "variable-2",
423 "\\": "keyword",
424 "\"": "comment"
383 };
425 };
384
426
385 function tlvGenIndent(stream, state) {
427 // Lines starting with these characters define scope (result in indentation).
386 var tlvindentUnit = 2;
428 var tlvScopePrefixChars = {
387 var rtnIndent = -1, indentUnitRq = 0, curIndent = stream.indentation();
429 "/": "beh-hier",
388 switch (state.tlvCurCtlFlowChar) {
430 ">": "beh-hier",
389 case "\\":
431 "-": "phys-hier",
390 curIndent = 0;
432 "|": "pipe",
391 break;
433 "?": "when",
392 case "|":
434 "@": "stage",
393 if (state.tlvPrevPrevCtlFlowChar == "@") {
435 "\\": "keyword"
394 indentUnitRq = -2; //-2 new pipe rq after cur pipe
436 };
395 break;
437 var tlvIndentUnit = 3;
396 }
438 var tlvTrackStatements = false;
397 if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar])
439 var tlvIdentMatch = /^([~!@#\$%\^&\*-\+=\?\/\\\|'"<>]+)([\d\w_]*)/; // Matches an identifiere.
398 indentUnitRq = 1; // +1 new scope
440 // Note that ':' is excluded, because of it's use in [:].
399 break;
441 var tlvFirstLevelIndentMatch = /^[! ] /;
400 case "M": // m4
442 var tlvLineIndentationMatch = /^[! ] */;
401 if (state.tlvPrevPrevCtlFlowChar == "@") {
443 var tlvCommentMatch = /^\/[\/\*]/;
402 indentUnitRq = -2; //-2 new inst rq after pipe
444
403 break;
445
446 // Returns a style specific to the scope at the given indentation column.
447 // Type is one of: "indent", "scope-ident", "before-scope-ident".
448 function tlvScopeStyle(state, indentation, type) {
449 // Begin scope.
450 var depth = indentation / tlvIndentUnit; // TODO: Pass this in instead.
451 return "tlv-" + state.tlvIndentationStyle[depth] + "-" + type;
404 }
452 }
405 if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar])
453
406 indentUnitRq = 1; // +1 new scope
454 // Return true if the next thing in the stream is an identifier with a mnemonic.
407 break;
455 function tlvIdentNext(stream) {
408 case "@":
456 var match;
409 if (state.tlvPrevCtlFlowChar == "S")
457 return (match = stream.match(tlvIdentMatch, false)) && match[2].length > 0;
410 indentUnitRq = -1; // new pipe stage after stmts
411 if (state.tlvPrevCtlFlowChar == "|")
412 indentUnitRq = 1; // 1st pipe stage
413 break;
414 case "S":
415 if (state.tlvPrevCtlFlowChar == "@")
416 indentUnitRq = 1; // flow in pipe stage
417 if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar])
418 indentUnitRq = 1; // +1 new scope
419 break;
420 }
421 var statementIndentUnit = tlvindentUnit;
422 rtnIndent = curIndent + (indentUnitRq*statementIndentUnit);
423 return rtnIndent >= 0 ? rtnIndent : curIndent;
424 }
458 }
425
459
426 CodeMirror.defineMIME("text/x-tlv", {
460 CodeMirror.defineMIME("text/x-tlv", {
427 name: "verilog",
461 name: "verilog",
462
428 hooks: {
463 hooks: {
429 "\\": function(stream, state) {
464
430 var vxIndent = 0, style = false;
465 electricInput: false,
431 var curPunc = stream.string;
466
432 if ((stream.sol()) && ((/\\SV/.test(stream.string)) || (/\\TLV/.test(stream.string)))) {
467
433 curPunc = (/\\TLV_version/.test(stream.string))
468 // Return undefined for verilog tokenizing, or style for TLV token (null not used).
434 ? "\\TLV_version" : stream.string;
469 // Standard CM styles are used for most formatting, but some TL-Verilog-specific highlighting
470 // can be enabled with the definition of cm-tlv-* styles, including highlighting for:
471 // - M4 tokens
472 // - TLV scope indentation
473 // - Statement delimitation (enabled by tlvTrackStatements)
474 token: function(stream, state) {
475 var style = undefined;
476 var match; // Return value of pattern matches.
477
478 // Set highlighting mode based on code region (TLV or SV).
479 if (stream.sol() && ! state.tlvInBlockComment) {
480 // Process region.
481 if (stream.peek() == '\\') {
482 style = "def";
435 stream.skipToEnd();
483 stream.skipToEnd();
436 if (curPunc == "\\SV" && state.vxCodeActive) {state.vxCodeActive = false;};
484 if (stream.string.match(/\\SV/)) {
437 if ((/\\TLV/.test(curPunc) && !state.vxCodeActive)
485 state.tlvCodeActive = false;
438 || (curPunc=="\\TLV_version" && state.vxCodeActive)) {state.vxCodeActive = true;};
486 } else if (stream.string.match(/\\TLV/)){
439 style = "keyword";
487 state.tlvCodeActive = true;
440 state.tlvCurCtlFlowChar = state.tlvPrevPrevCtlFlowChar
488 }
441 = state.tlvPrevCtlFlowChar = "";
489 }
442 if (state.vxCodeActive == true) {
490 // Correct indentation in the face of a line prefix char.
443 state.tlvCurCtlFlowChar = "\\";
491 if (state.tlvCodeActive && stream.pos == 0 &&
444 vxIndent = tlvGenIndent(stream, state);
492 (state.indented == 0) && (match = stream.match(tlvLineIndentationMatch, false))) {
493 state.indented = match[0].length;
445 }
494 }
446 state.vxIndentRq = vxIndent;
495
496 // Compute indentation state:
497 // o Auto indentation on next line
498 // o Indentation scope styles
499 var indented = state.indented;
500 var depth = indented / tlvIndentUnit;
501 if (depth <= state.tlvIndentationStyle.length) {
502 // not deeper than current scope
503
504 var blankline = stream.string.length == indented;
505 var chPos = depth * tlvIndentUnit;
506 if (chPos < stream.string.length) {
507 var bodyString = stream.string.slice(chPos);
508 var ch = bodyString[0];
509 if (tlvScopePrefixChars[ch] && ((match = bodyString.match(tlvIdentMatch)) &&
510 tlvIdentifierStyle[match[1]])) {
511 // This line begins scope.
512 // Next line gets indented one level.
513 indented += tlvIndentUnit;
514 // Style the next level of indentation (except non-region keyword identifiers,
515 // which are statements themselves)
516 if (!(ch == "\\" && chPos > 0)) {
517 state.tlvIndentationStyle[depth] = tlvScopePrefixChars[ch];
518 if (tlvTrackStatements) {state.statementComment = false;}
519 depth++;
520 }
521 }
447 }
522 }
448 return style;
523 // Clear out deeper indentation levels unless line is blank.
449 },
524 if (!blankline) {
450 tokenBase: function(stream, state) {
525 while (state.tlvIndentationStyle.length > depth) {
451 var vxIndent = 0, style = false;
526 state.tlvIndentationStyle.pop();
452 var tlvisOperatorChar = /[\[\]=:]/;
527 }
453 var tlvkpScopePrefixs = {
528 }
454 "**":"variable-2", "*":"variable-2", "$$":"variable", "$":"variable",
529 }
455 "^^":"attribute", "^":"attribute"};
530 // Set next level of indentation.
456 var ch = stream.peek();
531 state.tlvNextIndent = indented;
457 var vxCurCtlFlowCharValueAtStart = state.tlvCurCtlFlowChar;
532 }
458 if (state.vxCodeActive == true) {
533
459 if (/[\[\]{}\(\);\:]/.test(ch)) {
534 if (state.tlvCodeActive) {
460 // bypass nesting and 1 char punc
535 // Highlight as TLV.
461 style = "meta";
536
462 stream.next();
537 var beginStatement = false;
463 } else if (ch == "/") {
538 if (tlvTrackStatements) {
464 stream.next();
539 // This starts a statement if the position is at the scope level
465 if (stream.eat("/")) {
540 // and we're not within a statement leading comment.
466 stream.skipToEnd();
541 beginStatement =
467 style = "comment";
542 (stream.peek() != " ") && // not a space
468 state.tlvCurCtlFlowChar = "S";
543 (style === undefined) && // not a region identifier
544 !state.tlvInBlockComment && // not in block comment
545 //!stream.match(tlvCommentMatch, false) && // not comment start
546 (stream.column() == state.tlvIndentationStyle.length * tlvIndentUnit); // at scope level
547 if (beginStatement) {
548 if (state.statementComment) {
549 // statement already started by comment
550 beginStatement = false;
551 }
552 state.statementComment =
553 stream.match(tlvCommentMatch, false); // comment start
554 }
555 }
556
557 var match;
558 if (style !== undefined) {
559 // Region line.
560 style += " " + tlvScopeStyle(state, 0, "scope-ident")
561 } else if (((stream.pos / tlvIndentUnit) < state.tlvIndentationStyle.length) &&
562 (match = stream.match(stream.sol() ? tlvFirstLevelIndentMatch : /^ /))) {
563 // Indentation
564 style = // make this style distinct from the previous one to prevent
565 // codemirror from combining spans
566 "tlv-indent-" + (((stream.pos % 2) == 0) ? "even" : "odd") +
567 // and style it
568 " " + tlvScopeStyle(state, stream.pos - tlvIndentUnit, "indent");
569 // Style the line prefix character.
570 if (match[0].charAt(0) == "!") {
571 style += " tlv-alert-line-prefix";
572 }
573 // Place a class before a scope identifier.
574 if (tlvIdentNext(stream)) {
575 style += " " + tlvScopeStyle(state, stream.pos, "before-scope-ident");
576 }
577 } else if (state.tlvInBlockComment) {
578 // In a block comment.
579 if (stream.match(/^.*?\*\//)) {
580 // Exit block comment.
581 state.tlvInBlockComment = false;
582 if (tlvTrackStatements && !stream.eol()) {
583 // Anything after comment is assumed to be real statement content.
584 state.statementComment = false;
585 }
469 } else {
586 } else {
470 stream.backUp(1);
587 stream.skipToEnd();
588 }
589 style = "comment";
590 } else if ((match = stream.match(tlvCommentMatch)) && !state.tlvInBlockComment) {
591 // Start comment.
592 if (match[0] == "//") {
593 // Line comment.
594 stream.skipToEnd();
595 } else {
596 // Block comment.
597 state.tlvInBlockComment = true;
598 }
599 style = "comment";
600 } else if (match = stream.match(tlvIdentMatch)) {
601 // looks like an identifier (or identifier prefix)
602 var prefix = match[1];
603 var mnemonic = match[2];
604 if (// is identifier prefix
605 tlvIdentifierStyle.hasOwnProperty(prefix) &&
606 // has mnemonic or we're at the end of the line (maybe it hasn't been typed yet)
607 (mnemonic.length > 0 || stream.eol())) {
608 style = tlvIdentifierStyle[prefix];
609 if (stream.column() == state.indented) {
610 // Begin scope.
611 style += " " + tlvScopeStyle(state, stream.column(), "scope-ident")
471 }
612 }
472 } else if (ch == "@") {
613 } else {
473 // pipeline stage
614 // Just swallow one character and try again.
474 style = tlvchScopePrefixes[ch];
615 // This enables subsequent identifier match with preceding symbol character, which
475 state.tlvCurCtlFlowChar = "@";
616 // is legal within a statement. (Eg, !$reset). It also enables detection of
476 stream.next();
617 // comment start with preceding symbols.
477 stream.eatWhile(/[\w\$_]/);
618 stream.backUp(stream.current().length - 1);
478 } else if (stream.match(/\b[mM]4+/, true)) { // match: function(pattern, consume, caseInsensitive)
619 style = "tlv-default";
620 }
621 } else if (stream.match(/^\t+/)) {
622 // Highlight tabs, which are illegal.
623 style = "tlv-tab";
624 } else if (stream.match(/^[\[\]{}\(\);\:]+/)) {
625 // [:], (), {}, ;.
626 style = "meta";
627 } else if (match = stream.match(/^[mM]4([\+_])?[\w\d_]*/)) {
479 // m4 pre proc
628 // m4 pre proc
480 stream.skipTo("(");
629 style = (match[1] == "+") ? "tlv-m4-plus" : "tlv-m4";
481 style = "def";
630 } else if (stream.match(/^ +/)){
482 state.tlvCurCtlFlowChar = "M";
631 // Skip over spaces.
483 } else if (ch == "!" && stream.sol()) {
632 if (stream.eol()) {
484 // v stmt in tlv region
633 // Trailing spaces.
485 // state.tlvCurCtlFlowChar = "S";
634 style = "error";
486 style = "comment";
635 } else {
636 // Non-trailing spaces.
637 style = "tlv-default";
638 }
639 } else if (stream.match(/^[\w\d_]+/)) {
640 // alpha-numeric token.
641 style = "number";
642 } else {
643 // Eat the next char w/ no formatting.
487 stream.next();
644 stream.next();
488 } else if (tlvisOperatorChar.test(ch)) {
645 style = "tlv-default";
489 // operators
646 }
490 stream.eatWhile(tlvisOperatorChar);
647 if (beginStatement) {
491 style = "operator";
648 style += " tlv-statement";
492 } else if (ch == "#") {
493 // phy hier
494 state.tlvCurCtlFlowChar = (state.tlvCurCtlFlowChar == "")
495 ? ch : state.tlvCurCtlFlowChar;
496 stream.next();
497 stream.eatWhile(/[+-]\d/);
498 style = "tag";
499 } else if (tlvkpScopePrefixs.propertyIsEnumerable(ch)) {
500 // special TLV operators
501 style = tlvkpScopePrefixs[ch];
502 state.tlvCurCtlFlowChar = state.tlvCurCtlFlowChar == "" ? "S" : state.tlvCurCtlFlowChar; // stmt
503 stream.next();
504 stream.match(/[a-zA-Z_0-9]+/);
505 } else if (style = tlvchScopePrefixes[ch] || false) {
506 // special TLV operators
507 state.tlvCurCtlFlowChar = state.tlvCurCtlFlowChar == "" ? ch : state.tlvCurCtlFlowChar;
508 stream.next();
509 stream.match(/[a-zA-Z_0-9]+/);
510 }
649 }
511 if (state.tlvCurCtlFlowChar != vxCurCtlFlowCharValueAtStart) { // flow change
650 } else {
512 vxIndent = tlvGenIndent(stream, state);
651 if (stream.match(/^[mM]4([\w\d_]*)/)) {
513 state.vxIndentRq = vxIndent;
652 // m4 pre proc
653 style = "tlv-m4";
514 }
654 }
515 }
655 }
516 return style;
656 return style;
517 },
657 },
518 token: function(stream, state) {
658
519 if (state.vxCodeActive == true && stream.sol() && state.tlvCurCtlFlowChar != "") {
520 state.tlvPrevPrevCtlFlowChar = state.tlvPrevCtlFlowChar;
521 state.tlvPrevCtlFlowChar = state.tlvCurCtlFlowChar;
522 state.tlvCurCtlFlowChar = "";
523 }
524 },
525 indent: function(state) {
659 indent: function(state) {
526 return (state.vxCodeActive == true) ? state.vxIndentRq : -1;
660 return (state.tlvCodeActive == true) ? state.tlvNextIndent : -1;
527 },
661 },
662
528 startState: function(state) {
663 startState: function(state) {
529 state.tlvCurCtlFlowChar = "";
664 state.tlvIndentationStyle = []; // Styles to use for each level of indentation.
530 state.tlvPrevCtlFlowChar = "";
665 state.tlvCodeActive = true; // True when we're in a TLV region (and at beginning of file).
531 state.tlvPrevPrevCtlFlowChar = "";
666 state.tlvNextIndent = -1; // The number of spaces to autoindent the next line if tlvCodeActive.
532 state.vxCodeActive = true;
667 state.tlvInBlockComment = false; // True inside /**/ comment.
533 state.vxIndentRq = 0;
668 if (tlvTrackStatements) {
669 state.statementComment = false; // True inside a statement's header comment.
534 }
670 }
535 }
671 }
672
673 }
536 });
674 });
537 });
675 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Originally written by Alf Nielsen, re-written by Michael Zhou
4 // Originally written by Alf Nielsen, re-written by Michael Zhou
5 (function(mod) {
5 (function(mod) {
@@ -36,7 +36,7 b' CodeMirror.defineMode("vhdl", function(c'
36 multiLineStrings = parserConfig.multiLineStrings;
36 multiLineStrings = parserConfig.multiLineStrings;
37
37
38 var keywords = words("abs,access,after,alias,all,and,architecture,array,assert,attribute,begin,block," +
38 var keywords = words("abs,access,after,alias,all,and,architecture,array,assert,attribute,begin,block," +
39 "body,buffer,bus,case,component,configuration,constant,disconnent,downto,else,elsif,end,end block,end case," +
39 "body,buffer,bus,case,component,configuration,constant,disconnect,downto,else,elsif,end,end block,end case," +
40 "end component,end for,end generate,end if,end loop,end process,end record,end units,entity,exit,file,for," +
40 "end component,end for,end generate,end if,end loop,end process,end record,end units,entity,exit,file,for," +
41 "function,generate,generic,generic map,group,guarded,if,impure,in,inertial,inout,is,label,library,linkage," +
41 "function,generate,generic,generic map,group,guarded,if,impure,in,inertial,inout,is,label,library,linkage," +
42 "literal,loop,map,mod,nand,new,next,nor,null,of,on,open,or,others,out,package,package body,port,port map," +
42 "literal,loop,map,mod,nand,new,next,nor,null,of,on,open,or,others,out,package,package body,port,port map," +
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function (mod) {
4 (function (mod) {
5 "use strict";
5 "use strict";
@@ -12,7 +12,7 b''
12 require("../css/css"),
12 require("../css/css"),
13 require("../sass/sass"),
13 require("../sass/sass"),
14 require("../stylus/stylus"),
14 require("../stylus/stylus"),
15 require("../jade/jade"),
15 require("../pug/pug"),
16 require("../handlebars/handlebars"));
16 require("../handlebars/handlebars"));
17 } else if (typeof define === "function" && define.amd) { // AMD
17 } else if (typeof define === "function" && define.amd) { // AMD
18 define(["../../lib/codemirror",
18 define(["../../lib/codemirror",
@@ -23,7 +23,7 b''
23 "../css/css",
23 "../css/css",
24 "../sass/sass",
24 "../sass/sass",
25 "../stylus/stylus",
25 "../stylus/stylus",
26 "../jade/jade",
26 "../pug/pug",
27 "../handlebars/handlebars"], mod);
27 "../handlebars/handlebars"], mod);
28 } else { // Plain browser env
28 } else { // Plain browser env
29 mod(CodeMirror);
29 mod(CodeMirror);
@@ -32,19 +32,26 b''
32 var tagLanguages = {
32 var tagLanguages = {
33 script: [
33 script: [
34 ["lang", /coffee(script)?/, "coffeescript"],
34 ["lang", /coffee(script)?/, "coffeescript"],
35 ["type", /^(?:text|application)\/(?:x-)?coffee(?:script)?$/, "coffeescript"]
35 ["type", /^(?:text|application)\/(?:x-)?coffee(?:script)?$/, "coffeescript"],
36 ["lang", /^babel$/, "javascript"],
37 ["type", /^text\/babel$/, "javascript"],
38 ["type", /^text\/ecmascript-\d+$/, "javascript"]
36 ],
39 ],
37 style: [
40 style: [
38 ["lang", /^stylus$/i, "stylus"],
41 ["lang", /^stylus$/i, "stylus"],
39 ["lang", /^sass$/i, "sass"],
42 ["lang", /^sass$/i, "sass"],
43 ["lang", /^less$/i, "text/x-less"],
44 ["lang", /^scss$/i, "text/x-scss"],
40 ["type", /^(text\/)?(x-)?styl(us)?$/i, "stylus"],
45 ["type", /^(text\/)?(x-)?styl(us)?$/i, "stylus"],
41 ["type", /^text\/sass/i, "sass"]
46 ["type", /^text\/sass/i, "sass"],
47 ["type", /^(text\/)?(x-)?scss$/i, "text/x-scss"],
48 ["type", /^(text\/)?(x-)?less$/i, "text/x-less"]
42 ],
49 ],
43 template: [
50 template: [
44 ["lang", /^vue-template$/i, "vue"],
51 ["lang", /^vue-template$/i, "vue"],
45 ["lang", /^jade$/i, "jade"],
52 ["lang", /^pug$/i, "pug"],
46 ["lang", /^handlebars$/i, "handlebars"],
53 ["lang", /^handlebars$/i, "handlebars"],
47 ["type", /^(text\/)?(x-)?jade$/i, "jade"],
54 ["type", /^(text\/)?(x-)?pug$/i, "pug"],
48 ["type", /^text\/x-handlebars-template$/i, "handlebars"],
55 ["type", /^text\/x-handlebars-template$/i, "handlebars"],
49 [null, null, "vue-template"]
56 [null, null, "vue-template"]
50 ]
57 ]
@@ -63,7 +70,8 b''
63
70
64 CodeMirror.defineMode("vue", function (config) {
71 CodeMirror.defineMode("vue", function (config) {
65 return CodeMirror.getMode(config, {name: "htmlmixed", tags: tagLanguages});
72 return CodeMirror.getMode(config, {name: "htmlmixed", tags: tagLanguages});
66 }, "htmlmixed", "xml", "javascript", "coffeescript", "css", "sass", "stylus", "jade", "handlebars");
73 }, "htmlmixed", "xml", "javascript", "coffeescript", "css", "sass", "stylus", "pug", "handlebars");
67
74
68 CodeMirror.defineMIME("script/x-vue", "vue");
75 CodeMirror.defineMIME("script/x-vue", "vue");
76 CodeMirror.defineMIME("text/x-vue", "vue");
69 });
77 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -52,6 +52,7 b' var xmlConfig = {'
52 doNotIndent: {},
52 doNotIndent: {},
53 allowUnquoted: false,
53 allowUnquoted: false,
54 allowMissing: false,
54 allowMissing: false,
55 allowMissingTagName: false,
55 caseFold: false
56 caseFold: false
56 }
57 }
57
58
@@ -162,8 +163,9 b' CodeMirror.defineMode("xml", function(ed'
162 stream.next();
163 stream.next();
163 }
164 }
164 return style;
165 return style;
165 };
166 }
166 }
167 }
168
167 function doctype(depth) {
169 function doctype(depth) {
168 return function(stream, state) {
170 return function(stream, state) {
169 var ch;
171 var ch;
@@ -226,6 +228,9 b' CodeMirror.defineMode("xml", function(ed'
226 state.tagName = stream.current();
228 state.tagName = stream.current();
227 setStyle = "tag";
229 setStyle = "tag";
228 return attrState;
230 return attrState;
231 } else if (config.allowMissingTagName && type == "endTag") {
232 setStyle = "tag bracket";
233 return attrState(type, stream, state);
229 } else {
234 } else {
230 setStyle = "error";
235 setStyle = "error";
231 return tagNameState;
236 return tagNameState;
@@ -237,13 +242,16 b' CodeMirror.defineMode("xml", function(ed'
237 if (state.context && state.context.tagName != tagName &&
242 if (state.context && state.context.tagName != tagName &&
238 config.implicitlyClosed.hasOwnProperty(state.context.tagName))
243 config.implicitlyClosed.hasOwnProperty(state.context.tagName))
239 popContext(state);
244 popContext(state);
240 if (state.context && state.context.tagName == tagName) {
245 if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
241 setStyle = "tag";
246 setStyle = "tag";
242 return closeState;
247 return closeState;
243 } else {
248 } else {
244 setStyle = "tag error";
249 setStyle = "tag error";
245 return closeStateErr;
250 return closeStateErr;
246 }
251 }
252 } else if (config.allowMissingTagName && type == "endTag") {
253 setStyle = "tag bracket";
254 return closeState(type, stream, state);
247 } else {
255 } else {
248 setStyle = "error";
256 setStyle = "error";
249 return closeStateErr;
257 return closeStateErr;
@@ -382,6 +390,17 b' CodeMirror.defineMode("xml", function(ed'
382 skipAttribute: function(state) {
390 skipAttribute: function(state) {
383 if (state.state == attrValueState)
391 if (state.state == attrValueState)
384 state.state = attrState
392 state.state = attrState
393 },
394
395 xmlCurrentTag: function(state) {
396 return state.tagName ? {name: state.tagName, close: state.type == "closeTag"} : null
397 },
398
399 xmlCurrentContext: function(state) {
400 var context = []
401 for (var cx = state.context; cx; cx = cx.prev)
402 if (cx.tagName) context.push(cx.tagName)
403 return context.reverse()
385 }
404 }
386 };
405 };
387 });
406 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -17,43 +17,54 b' CodeMirror.defineMode("xquery", function'
17 // function. Each keyword is a property of the keywords object whose
17 // function. Each keyword is a property of the keywords object whose
18 // value is {type: atype, style: astyle}
18 // value is {type: atype, style: astyle}
19 var keywords = function(){
19 var keywords = function(){
20 // conveinence functions used to build keywords object
20 // convenience functions used to build keywords object
21 function kw(type) {return {type: type, style: "keyword"};}
21 function kw(type) {return {type: type, style: "keyword"};}
22 var A = kw("keyword a")
22 var operator = kw("operator")
23 , B = kw("keyword b")
24 , C = kw("keyword c")
25 , operator = kw("operator")
26 , atom = {type: "atom", style: "atom"}
23 , atom = {type: "atom", style: "atom"}
27 , punctuation = {type: "punctuation", style: null}
24 , punctuation = {type: "punctuation", style: null}
28 , qualifier = {type: "axis_specifier", style: "qualifier"};
25 , qualifier = {type: "axis_specifier", style: "qualifier"};
29
26
30 // kwObj is what is return from this function at the end
27 // kwObj is what is return from this function at the end
31 var kwObj = {
28 var kwObj = {
32 'if': A, 'switch': A, 'while': A, 'for': A,
29 ',': punctuation
33 'else': B, 'then': B, 'try': B, 'finally': B, 'catch': B,
34 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C,
35 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C,
36 ',': punctuation,
37 'null': atom, 'fn:false()': atom, 'fn:true()': atom
38 };
30 };
39
31
40 // a list of 'basic' keywords. For each add a property to kwObj with the value of
32 // a list of 'basic' keywords. For each add a property to kwObj with the value of
41 // {type: basic[i], style: "keyword"} e.g. 'after' --> {type: "after", style: "keyword"}
33 // {type: basic[i], style: "keyword"} e.g. 'after' --> {type: "after", style: "keyword"}
42 var basic = ['after','ancestor','ancestor-or-self','and','as','ascending','assert','attribute','before',
34 var basic = ['after', 'all', 'allowing', 'ancestor', 'ancestor-or-self', 'any', 'array', 'as',
43 'by','case','cast','child','comment','declare','default','define','descendant','descendant-or-self',
35 'ascending', 'at', 'attribute', 'base-uri', 'before', 'boundary-space', 'by', 'case', 'cast',
44 'descending','document','document-node','element','else','eq','every','except','external','following',
36 'castable', 'catch', 'child', 'collation', 'comment', 'construction', 'contains', 'content',
45 'following-sibling','follows','for','function','if','import','in','instance','intersect','item',
37 'context', 'copy', 'copy-namespaces', 'count', 'decimal-format', 'declare', 'default', 'delete',
46 'let','module','namespace','node','node','of','only','or','order','parent','precedes','preceding',
38 'descendant', 'descendant-or-self', 'descending', 'diacritics', 'different', 'distance',
47 'preceding-sibling','processing-instruction','ref','return','returns','satisfies','schema','schema-element',
39 'document', 'document-node', 'element', 'else', 'empty', 'empty-sequence', 'encoding', 'end',
48 'self','some','sortby','stable','text','then','to','treat','typeswitch','union','variable','version','where',
40 'entire', 'every', 'exactly', 'except', 'external', 'first', 'following', 'following-sibling',
49 'xquery', 'empty-sequence'];
41 'for', 'from', 'ftand', 'ftnot', 'ft-option', 'ftor', 'function', 'fuzzy', 'greatest', 'group',
42 'if', 'import', 'in', 'inherit', 'insensitive', 'insert', 'instance', 'intersect', 'into',
43 'invoke', 'is', 'item', 'language', 'last', 'lax', 'least', 'let', 'levels', 'lowercase', 'map',
44 'modify', 'module', 'most', 'namespace', 'next', 'no', 'node', 'nodes', 'no-inherit',
45 'no-preserve', 'not', 'occurs', 'of', 'only', 'option', 'order', 'ordered', 'ordering',
46 'paragraph', 'paragraphs', 'parent', 'phrase', 'preceding', 'preceding-sibling', 'preserve',
47 'previous', 'processing-instruction', 'relationship', 'rename', 'replace', 'return',
48 'revalidation', 'same', 'satisfies', 'schema', 'schema-attribute', 'schema-element', 'score',
49 'self', 'sensitive', 'sentence', 'sentences', 'sequence', 'skip', 'sliding', 'some', 'stable',
50 'start', 'stemming', 'stop', 'strict', 'strip', 'switch', 'text', 'then', 'thesaurus', 'times',
51 'to', 'transform', 'treat', 'try', 'tumbling', 'type', 'typeswitch', 'union', 'unordered',
52 'update', 'updating', 'uppercase', 'using', 'validate', 'value', 'variable', 'version',
53 'weight', 'when', 'where', 'wildcards', 'window', 'with', 'without', 'word', 'words', 'xquery'];
50 for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i]);};
54 for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i]);};
51
55
52 // a list of types. For each add a property to kwObj with the value of
56 // a list of types. For each add a property to kwObj with the value of
53 // {type: "atom", style: "atom"}
57 // {type: "atom", style: "atom"}
54 var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime',
58 var types = ['xs:anyAtomicType', 'xs:anySimpleType', 'xs:anyType', 'xs:anyURI',
55 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary',
59 'xs:base64Binary', 'xs:boolean', 'xs:byte', 'xs:date', 'xs:dateTime', 'xs:dateTimeStamp',
56 'xs:base64Binary', 'xs:anyURI', 'xs:QName', 'xs:byte','xs:boolean','xs:anyURI','xf:yearMonthDuration'];
60 'xs:dayTimeDuration', 'xs:decimal', 'xs:double', 'xs:duration', 'xs:ENTITIES', 'xs:ENTITY',
61 'xs:float', 'xs:gDay', 'xs:gMonth', 'xs:gMonthDay', 'xs:gYear', 'xs:gYearMonth', 'xs:hexBinary',
62 'xs:ID', 'xs:IDREF', 'xs:IDREFS', 'xs:int', 'xs:integer', 'xs:item', 'xs:java', 'xs:language',
63 'xs:long', 'xs:Name', 'xs:NCName', 'xs:negativeInteger', 'xs:NMTOKEN', 'xs:NMTOKENS',
64 'xs:nonNegativeInteger', 'xs:nonPositiveInteger', 'xs:normalizedString', 'xs:NOTATION',
65 'xs:numeric', 'xs:positiveInteger', 'xs:precisionDecimal', 'xs:QName', 'xs:short', 'xs:string',
66 'xs:time', 'xs:token', 'xs:unsignedByte', 'xs:unsignedInt', 'xs:unsignedLong',
67 'xs:unsignedShort', 'xs:untyped', 'xs:untypedAtomic', 'xs:yearMonthDuration'];
57 for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;};
68 for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;};
58
69
59 // each operator will add a property to kwObj with value of {type: "operator", style: "keyword"}
70 // each operator will add a property to kwObj with value of {type: "operator", style: "keyword"}
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function (mod) {
4 (function (mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -45,7 +45,7 b''
45 return innerMode.token(stream, state.inner)
45 return innerMode.token(stream, state.inner)
46 }
46 }
47 } else if (state.state == FRONTMATTER) {
47 } else if (state.state == FRONTMATTER) {
48 var end = stream.sol() && stream.match(/---/, false)
48 var end = stream.sol() && stream.match(/(---|\.\.\.)/, false)
49 var style = yamlMode.token(stream, state.inner)
49 var style = yamlMode.token(stream, state.inner)
50 if (end) {
50 if (end) {
51 state.state = BODY
51 state.state = BODY
@@ -65,4 +65,4 b''
65 }
65 }
66 }
66 }
67 })
67 })
68 })
68 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -108,10 +108,13 b' CodeMirror.defineMode("yaml", function()'
108 literal: false,
108 literal: false,
109 escaped: false
109 escaped: false
110 };
110 };
111 }
111 },
112 lineComment: "#",
113 fold: "indent"
112 };
114 };
113 });
115 });
114
116
115 CodeMirror.defineMIME("text/x-yaml", "yaml");
117 CodeMirror.defineMIME("text/x-yaml", "yaml");
118 CodeMirror.defineMIME("text/yaml", "yaml");
116
119
117 });
120 });
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
This diff has been collapsed as it changes many lines, (17493 lines changed) Show them Hide them
@@ -1,23 +1,17 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // This is CodeMirror (http://codemirror.net), a code editor
4 // This is CodeMirror (https://codemirror.net), a code editor
5 // implemented in JavaScript on top of the browser's DOM.
5 // implemented in JavaScript on top of the browser's DOM.
6 //
6 //
7 // You can find some technical background for some of the code below
7 // You can find some technical background for some of the code below
8 // at http://marijnhaverbeke.nl/blog/#cm-internals .
8 // at http://marijnhaverbeke.nl/blog/#cm-internals .
9
9
10 (function(mod) {
10 (function (global, factory) {
11 if (typeof exports == "object" && typeof module == "object") // CommonJS
11 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
12 module.exports = mod();
12 typeof define === 'function' && define.amd ? define(factory) :
13 else if (typeof define == "function" && define.amd) // AMD
13 (global.CodeMirror = factory());
14 return define([], mod);
14 }(this, (function () { 'use strict';
15 else // Plain browser env
16 (this || window).CodeMirror = mod();
17 })(function() {
18 "use strict";
19
20 // BROWSER SNIFFING
21
15
22 // Kludges for bugs and behavior differences that can't be feature
16 // Kludges for bugs and behavior differences that can't be feature
23 // detected are enabled based on userAgent etc sniffing.
17 // detected are enabled based on userAgent etc sniffing.
@@ -27,113 +21,4314 b''
27 var gecko = /gecko\/\d/i.test(userAgent);
21 var gecko = /gecko\/\d/i.test(userAgent);
28 var ie_upto10 = /MSIE \d/.test(userAgent);
22 var ie_upto10 = /MSIE \d/.test(userAgent);
29 var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
23 var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
30 var ie = ie_upto10 || ie_11up;
24 var edge = /Edge\/(\d+)/.exec(userAgent);
31 var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
25 var ie = ie_upto10 || ie_11up || edge;
32 var webkit = /WebKit\//.test(userAgent);
26 var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
27 var webkit = !edge && /WebKit\//.test(userAgent);
33 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
28 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
34 var chrome = /Chrome\//.test(userAgent);
29 var chrome = !edge && /Chrome\//.test(userAgent);
35 var presto = /Opera\//.test(userAgent);
30 var presto = /Opera\//.test(userAgent);
36 var safari = /Apple Computer/.test(navigator.vendor);
31 var safari = /Apple Computer/.test(navigator.vendor);
37 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
32 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
38 var phantom = /PhantomJS/.test(userAgent);
33 var phantom = /PhantomJS/.test(userAgent);
39
34
40 var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
35 var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
36 var android = /Android/.test(userAgent);
41 // This is woefully incomplete. Suggestions for alternative methods welcome.
37 // This is woefully incomplete. Suggestions for alternative methods welcome.
42 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
38 var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
43 var mac = ios || /Mac/.test(platform);
39 var mac = ios || /Mac/.test(platform);
40 var chromeOS = /\bCrOS\b/.test(userAgent);
44 var windows = /win/i.test(platform);
41 var windows = /win/i.test(platform);
45
42
46 var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
43 var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
47 if (presto_version) presto_version = Number(presto_version[1]);
44 if (presto_version) { presto_version = Number(presto_version[1]); }
48 if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
45 if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
49 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
46 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
50 var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
47 var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
51 var captureRightClick = gecko || (ie && ie_version >= 9);
48 var captureRightClick = gecko || (ie && ie_version >= 9);
52
49
50 function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
51
52 var rmClass = function(node, cls) {
53 var current = node.className;
54 var match = classTest(cls).exec(current);
55 if (match) {
56 var after = current.slice(match.index + match[0].length);
57 node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
58 }
59 };
60
61 function removeChildren(e) {
62 for (var count = e.childNodes.length; count > 0; --count)
63 { e.removeChild(e.firstChild); }
64 return e
65 }
66
67 function removeChildrenAndAdd(parent, e) {
68 return removeChildren(parent).appendChild(e)
69 }
70
71 function elt(tag, content, className, style) {
72 var e = document.createElement(tag);
73 if (className) { e.className = className; }
74 if (style) { e.style.cssText = style; }
75 if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
76 else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
77 return e
78 }
79 // wrapper for elt, which removes the elt from the accessibility tree
80 function eltP(tag, content, className, style) {
81 var e = elt(tag, content, className, style);
82 e.setAttribute("role", "presentation");
83 return e
84 }
85
86 var range;
87 if (document.createRange) { range = function(node, start, end, endNode) {
88 var r = document.createRange();
89 r.setEnd(endNode || node, end);
90 r.setStart(node, start);
91 return r
92 }; }
93 else { range = function(node, start, end) {
94 var r = document.body.createTextRange();
95 try { r.moveToElementText(node.parentNode); }
96 catch(e) { return r }
97 r.collapse(true);
98 r.moveEnd("character", end);
99 r.moveStart("character", start);
100 return r
101 }; }
102
103 function contains(parent, child) {
104 if (child.nodeType == 3) // Android browser always returns false when child is a textnode
105 { child = child.parentNode; }
106 if (parent.contains)
107 { return parent.contains(child) }
108 do {
109 if (child.nodeType == 11) { child = child.host; }
110 if (child == parent) { return true }
111 } while (child = child.parentNode)
112 }
113
114 function activeElt() {
115 // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
116 // IE < 10 will throw when accessed while the page is loading or in an iframe.
117 // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
118 var activeElement;
119 try {
120 activeElement = document.activeElement;
121 } catch(e) {
122 activeElement = document.body || null;
123 }
124 while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
125 { activeElement = activeElement.shadowRoot.activeElement; }
126 return activeElement
127 }
128
129 function addClass(node, cls) {
130 var current = node.className;
131 if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
132 }
133 function joinClasses(a, b) {
134 var as = a.split(" ");
135 for (var i = 0; i < as.length; i++)
136 { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
137 return b
138 }
139
140 var selectInput = function(node) { node.select(); };
141 if (ios) // Mobile Safari apparently has a bug where select() is broken.
142 { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
143 else if (ie) // Suppress mysterious IE10 errors
144 { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
145
146 function bind(f) {
147 var args = Array.prototype.slice.call(arguments, 1);
148 return function(){return f.apply(null, args)}
149 }
150
151 function copyObj(obj, target, overwrite) {
152 if (!target) { target = {}; }
153 for (var prop in obj)
154 { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
155 { target[prop] = obj[prop]; } }
156 return target
157 }
158
159 // Counts the column offset in a string, taking tabs into account.
160 // Used mostly to find indentation.
161 function countColumn(string, end, tabSize, startIndex, startValue) {
162 if (end == null) {
163 end = string.search(/[^\s\u00a0]/);
164 if (end == -1) { end = string.length; }
165 }
166 for (var i = startIndex || 0, n = startValue || 0;;) {
167 var nextTab = string.indexOf("\t", i);
168 if (nextTab < 0 || nextTab >= end)
169 { return n + (end - i) }
170 n += nextTab - i;
171 n += tabSize - (n % tabSize);
172 i = nextTab + 1;
173 }
174 }
175
176 var Delayed = function() {
177 this.id = null;
178 this.f = null;
179 this.time = 0;
180 this.handler = bind(this.onTimeout, this);
181 };
182 Delayed.prototype.onTimeout = function (self) {
183 self.id = 0;
184 if (self.time <= +new Date) {
185 self.f();
186 } else {
187 setTimeout(self.handler, self.time - +new Date);
188 }
189 };
190 Delayed.prototype.set = function (ms, f) {
191 this.f = f;
192 var time = +new Date + ms;
193 if (!this.id || time < this.time) {
194 clearTimeout(this.id);
195 this.id = setTimeout(this.handler, ms);
196 this.time = time;
197 }
198 };
199
200 function indexOf(array, elt) {
201 for (var i = 0; i < array.length; ++i)
202 { if (array[i] == elt) { return i } }
203 return -1
204 }
205
206 // Number of pixels added to scroller and sizer to hide scrollbar
207 var scrollerGap = 30;
208
209 // Returned or thrown by various protocols to signal 'I'm not
210 // handling this'.
211 var Pass = {toString: function(){return "CodeMirror.Pass"}};
212
213 // Reused option objects for setSelection & friends
214 var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
215
216 // The inverse of countColumn -- find the offset that corresponds to
217 // a particular column.
218 function findColumn(string, goal, tabSize) {
219 for (var pos = 0, col = 0;;) {
220 var nextTab = string.indexOf("\t", pos);
221 if (nextTab == -1) { nextTab = string.length; }
222 var skipped = nextTab - pos;
223 if (nextTab == string.length || col + skipped >= goal)
224 { return pos + Math.min(skipped, goal - col) }
225 col += nextTab - pos;
226 col += tabSize - (col % tabSize);
227 pos = nextTab + 1;
228 if (col >= goal) { return pos }
229 }
230 }
231
232 var spaceStrs = [""];
233 function spaceStr(n) {
234 while (spaceStrs.length <= n)
235 { spaceStrs.push(lst(spaceStrs) + " "); }
236 return spaceStrs[n]
237 }
238
239 function lst(arr) { return arr[arr.length-1] }
240
241 function map(array, f) {
242 var out = [];
243 for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
244 return out
245 }
246
247 function insertSorted(array, value, score) {
248 var pos = 0, priority = score(value);
249 while (pos < array.length && score(array[pos]) <= priority) { pos++; }
250 array.splice(pos, 0, value);
251 }
252
253 function nothing() {}
254
255 function createObj(base, props) {
256 var inst;
257 if (Object.create) {
258 inst = Object.create(base);
259 } else {
260 nothing.prototype = base;
261 inst = new nothing();
262 }
263 if (props) { copyObj(props, inst); }
264 return inst
265 }
266
267 var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
268 function isWordCharBasic(ch) {
269 return /\w/.test(ch) || ch > "\x80" &&
270 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
271 }
272 function isWordChar(ch, helper) {
273 if (!helper) { return isWordCharBasic(ch) }
274 if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
275 return helper.test(ch)
276 }
277
278 function isEmpty(obj) {
279 for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
280 return true
281 }
282
283 // Extending unicode characters. A series of a non-extending char +
284 // any number of extending chars is treated as a single unit as far
285 // as editing and measuring is concerned. This is not fully correct,
286 // since some scripts/fonts/browsers also treat other configurations
287 // of code points as a group.
288 var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
289 function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
290
291 // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
292 function skipExtendingChars(str, pos, dir) {
293 while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
294 return pos
295 }
296
297 // Returns the value from the range [`from`; `to`] that satisfies
298 // `pred` and is closest to `from`. Assumes that at least `to`
299 // satisfies `pred`. Supports `from` being greater than `to`.
300 function findFirst(pred, from, to) {
301 // At any point we are certain `to` satisfies `pred`, don't know
302 // whether `from` does.
303 var dir = from > to ? -1 : 1;
304 for (;;) {
305 if (from == to) { return from }
306 var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
307 if (mid == from) { return pred(mid) ? from : to }
308 if (pred(mid)) { to = mid; }
309 else { from = mid + dir; }
310 }
311 }
312
313 // BIDI HELPERS
314
315 function iterateBidiSections(order, from, to, f) {
316 if (!order) { return f(from, to, "ltr", 0) }
317 var found = false;
318 for (var i = 0; i < order.length; ++i) {
319 var part = order[i];
320 if (part.from < to && part.to > from || from == to && part.to == from) {
321 f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
322 found = true;
323 }
324 }
325 if (!found) { f(from, to, "ltr"); }
326 }
327
328 var bidiOther = null;
329 function getBidiPartAt(order, ch, sticky) {
330 var found;
331 bidiOther = null;
332 for (var i = 0; i < order.length; ++i) {
333 var cur = order[i];
334 if (cur.from < ch && cur.to > ch) { return i }
335 if (cur.to == ch) {
336 if (cur.from != cur.to && sticky == "before") { found = i; }
337 else { bidiOther = i; }
338 }
339 if (cur.from == ch) {
340 if (cur.from != cur.to && sticky != "before") { found = i; }
341 else { bidiOther = i; }
342 }
343 }
344 return found != null ? found : bidiOther
345 }
346
347 // Bidirectional ordering algorithm
348 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
349 // that this (partially) implements.
350
351 // One-char codes used for character types:
352 // L (L): Left-to-Right
353 // R (R): Right-to-Left
354 // r (AL): Right-to-Left Arabic
355 // 1 (EN): European Number
356 // + (ES): European Number Separator
357 // % (ET): European Number Terminator
358 // n (AN): Arabic Number
359 // , (CS): Common Number Separator
360 // m (NSM): Non-Spacing Mark
361 // b (BN): Boundary Neutral
362 // s (B): Paragraph Separator
363 // t (S): Segment Separator
364 // w (WS): Whitespace
365 // N (ON): Other Neutrals
366
367 // Returns null if characters are ordered as they appear
368 // (left-to-right), or an array of sections ({from, to, level}
369 // objects) in the order in which they occur visually.
370 var bidiOrdering = (function() {
371 // Character types for codepoints 0 to 0xff
372 var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
373 // Character types for codepoints 0x600 to 0x6f9
374 var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
375 function charType(code) {
376 if (code <= 0xf7) { return lowTypes.charAt(code) }
377 else if (0x590 <= code && code <= 0x5f4) { return "R" }
378 else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
379 else if (0x6ee <= code && code <= 0x8ac) { return "r" }
380 else if (0x2000 <= code && code <= 0x200b) { return "w" }
381 else if (code == 0x200c) { return "b" }
382 else { return "L" }
383 }
384
385 var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
386 var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
387
388 function BidiSpan(level, from, to) {
389 this.level = level;
390 this.from = from; this.to = to;
391 }
392
393 return function(str, direction) {
394 var outerType = direction == "ltr" ? "L" : "R";
395
396 if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
397 var len = str.length, types = [];
398 for (var i = 0; i < len; ++i)
399 { types.push(charType(str.charCodeAt(i))); }
400
401 // W1. Examine each non-spacing mark (NSM) in the level run, and
402 // change the type of the NSM to the type of the previous
403 // character. If the NSM is at the start of the level run, it will
404 // get the type of sor.
405 for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
406 var type = types[i$1];
407 if (type == "m") { types[i$1] = prev; }
408 else { prev = type; }
409 }
410
411 // W2. Search backwards from each instance of a European number
412 // until the first strong type (R, L, AL, or sor) is found. If an
413 // AL is found, change the type of the European number to Arabic
414 // number.
415 // W3. Change all ALs to R.
416 for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
417 var type$1 = types[i$2];
418 if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
419 else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
420 }
421
422 // W4. A single European separator between two European numbers
423 // changes to a European number. A single common separator between
424 // two numbers of the same type changes to that type.
425 for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
426 var type$2 = types[i$3];
427 if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
428 else if (type$2 == "," && prev$1 == types[i$3+1] &&
429 (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
430 prev$1 = type$2;
431 }
432
433 // W5. A sequence of European terminators adjacent to European
434 // numbers changes to all European numbers.
435 // W6. Otherwise, separators and terminators change to Other
436 // Neutral.
437 for (var i$4 = 0; i$4 < len; ++i$4) {
438 var type$3 = types[i$4];
439 if (type$3 == ",") { types[i$4] = "N"; }
440 else if (type$3 == "%") {
441 var end = (void 0);
442 for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
443 var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
444 for (var j = i$4; j < end; ++j) { types[j] = replace; }
445 i$4 = end - 1;
446 }
447 }
448
449 // W7. Search backwards from each instance of a European number
450 // until the first strong type (R, L, or sor) is found. If an L is
451 // found, then change the type of the European number to L.
452 for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
453 var type$4 = types[i$5];
454 if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
455 else if (isStrong.test(type$4)) { cur$1 = type$4; }
456 }
457
458 // N1. A sequence of neutrals takes the direction of the
459 // surrounding strong text if the text on both sides has the same
460 // direction. European and Arabic numbers act as if they were R in
461 // terms of their influence on neutrals. Start-of-level-run (sor)
462 // and end-of-level-run (eor) are used at level run boundaries.
463 // N2. Any remaining neutrals take the embedding direction.
464 for (var i$6 = 0; i$6 < len; ++i$6) {
465 if (isNeutral.test(types[i$6])) {
466 var end$1 = (void 0);
467 for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
468 var before = (i$6 ? types[i$6-1] : outerType) == "L";
469 var after = (end$1 < len ? types[end$1] : outerType) == "L";
470 var replace$1 = before == after ? (before ? "L" : "R") : outerType;
471 for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
472 i$6 = end$1 - 1;
473 }
474 }
475
476 // Here we depart from the documented algorithm, in order to avoid
477 // building up an actual levels array. Since there are only three
478 // levels (0, 1, 2) in an implementation that doesn't take
479 // explicit embedding into account, we can build up the order on
480 // the fly, without following the level-based algorithm.
481 var order = [], m;
482 for (var i$7 = 0; i$7 < len;) {
483 if (countsAsLeft.test(types[i$7])) {
484 var start = i$7;
485 for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
486 order.push(new BidiSpan(0, start, i$7));
487 } else {
488 var pos = i$7, at = order.length;
489 for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
490 for (var j$2 = pos; j$2 < i$7;) {
491 if (countsAsNum.test(types[j$2])) {
492 if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
493 var nstart = j$2;
494 for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
495 order.splice(at, 0, new BidiSpan(2, nstart, j$2));
496 pos = j$2;
497 } else { ++j$2; }
498 }
499 if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
500 }
501 }
502 if (direction == "ltr") {
503 if (order[0].level == 1 && (m = str.match(/^\s+/))) {
504 order[0].from = m[0].length;
505 order.unshift(new BidiSpan(0, 0, m[0].length));
506 }
507 if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
508 lst(order).to -= m[0].length;
509 order.push(new BidiSpan(0, len - m[0].length, len));
510 }
511 }
512
513 return direction == "rtl" ? order.reverse() : order
514 }
515 })();
516
517 // Get the bidi ordering for the given line (and cache it). Returns
518 // false for lines that are fully left-to-right, and an array of
519 // BidiSpan objects otherwise.
520 function getOrder(line, direction) {
521 var order = line.order;
522 if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
523 return order
524 }
525
526 // EVENT HANDLING
527
528 // Lightweight event framework. on/off also work on DOM nodes,
529 // registering native DOM handlers.
530
531 var noHandlers = [];
532
533 var on = function(emitter, type, f) {
534 if (emitter.addEventListener) {
535 emitter.addEventListener(type, f, false);
536 } else if (emitter.attachEvent) {
537 emitter.attachEvent("on" + type, f);
538 } else {
539 var map$$1 = emitter._handlers || (emitter._handlers = {});
540 map$$1[type] = (map$$1[type] || noHandlers).concat(f);
541 }
542 };
543
544 function getHandlers(emitter, type) {
545 return emitter._handlers && emitter._handlers[type] || noHandlers
546 }
547
548 function off(emitter, type, f) {
549 if (emitter.removeEventListener) {
550 emitter.removeEventListener(type, f, false);
551 } else if (emitter.detachEvent) {
552 emitter.detachEvent("on" + type, f);
553 } else {
554 var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
555 if (arr) {
556 var index = indexOf(arr, f);
557 if (index > -1)
558 { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
559 }
560 }
561 }
562
563 function signal(emitter, type /*, values...*/) {
564 var handlers = getHandlers(emitter, type);
565 if (!handlers.length) { return }
566 var args = Array.prototype.slice.call(arguments, 2);
567 for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
568 }
569
570 // The DOM events that CodeMirror handles can be overridden by
571 // registering a (non-DOM) handler on the editor for the event name,
572 // and preventDefault-ing the event in that handler.
573 function signalDOMEvent(cm, e, override) {
574 if (typeof e == "string")
575 { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
576 signal(cm, override || e.type, cm, e);
577 return e_defaultPrevented(e) || e.codemirrorIgnore
578 }
579
580 function signalCursorActivity(cm) {
581 var arr = cm._handlers && cm._handlers.cursorActivity;
582 if (!arr) { return }
583 var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
584 for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
585 { set.push(arr[i]); } }
586 }
587
588 function hasHandler(emitter, type) {
589 return getHandlers(emitter, type).length > 0
590 }
591
592 // Add on and off methods to a constructor's prototype, to make
593 // registering events on such objects more convenient.
594 function eventMixin(ctor) {
595 ctor.prototype.on = function(type, f) {on(this, type, f);};
596 ctor.prototype.off = function(type, f) {off(this, type, f);};
597 }
598
599 // Due to the fact that we still support jurassic IE versions, some
600 // compatibility wrappers are needed.
601
602 function e_preventDefault(e) {
603 if (e.preventDefault) { e.preventDefault(); }
604 else { e.returnValue = false; }
605 }
606 function e_stopPropagation(e) {
607 if (e.stopPropagation) { e.stopPropagation(); }
608 else { e.cancelBubble = true; }
609 }
610 function e_defaultPrevented(e) {
611 return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
612 }
613 function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
614
615 function e_target(e) {return e.target || e.srcElement}
616 function e_button(e) {
617 var b = e.which;
618 if (b == null) {
619 if (e.button & 1) { b = 1; }
620 else if (e.button & 2) { b = 3; }
621 else if (e.button & 4) { b = 2; }
622 }
623 if (mac && e.ctrlKey && b == 1) { b = 3; }
624 return b
625 }
626
627 // Detect drag-and-drop
628 var dragAndDrop = function() {
629 // There is *some* kind of drag-and-drop support in IE6-8, but I
630 // couldn't get it to work yet.
631 if (ie && ie_version < 9) { return false }
632 var div = elt('div');
633 return "draggable" in div || "dragDrop" in div
634 }();
635
636 var zwspSupported;
637 function zeroWidthElement(measure) {
638 if (zwspSupported == null) {
639 var test = elt("span", "\u200b");
640 removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
641 if (measure.firstChild.offsetHeight != 0)
642 { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
643 }
644 var node = zwspSupported ? elt("span", "\u200b") :
645 elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
646 node.setAttribute("cm-text", "");
647 return node
648 }
649
650 // Feature-detect IE's crummy client rect reporting for bidi text
651 var badBidiRects;
652 function hasBadBidiRects(measure) {
653 if (badBidiRects != null) { return badBidiRects }
654 var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
655 var r0 = range(txt, 0, 1).getBoundingClientRect();
656 var r1 = range(txt, 1, 2).getBoundingClientRect();
657 removeChildren(measure);
658 if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
659 return badBidiRects = (r1.right - r0.right < 3)
660 }
661
662 // See if "".split is the broken IE version, if so, provide an
663 // alternative way to split lines.
664 var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
665 var pos = 0, result = [], l = string.length;
666 while (pos <= l) {
667 var nl = string.indexOf("\n", pos);
668 if (nl == -1) { nl = string.length; }
669 var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
670 var rt = line.indexOf("\r");
671 if (rt != -1) {
672 result.push(line.slice(0, rt));
673 pos += rt + 1;
674 } else {
675 result.push(line);
676 pos = nl + 1;
677 }
678 }
679 return result
680 } : function (string) { return string.split(/\r\n?|\n/); };
681
682 var hasSelection = window.getSelection ? function (te) {
683 try { return te.selectionStart != te.selectionEnd }
684 catch(e) { return false }
685 } : function (te) {
686 var range$$1;
687 try {range$$1 = te.ownerDocument.selection.createRange();}
688 catch(e) {}
689 if (!range$$1 || range$$1.parentElement() != te) { return false }
690 return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
691 };
692
693 var hasCopyEvent = (function () {
694 var e = elt("div");
695 if ("oncopy" in e) { return true }
696 e.setAttribute("oncopy", "return;");
697 return typeof e.oncopy == "function"
698 })();
699
700 var badZoomedRects = null;
701 function hasBadZoomedRects(measure) {
702 if (badZoomedRects != null) { return badZoomedRects }
703 var node = removeChildrenAndAdd(measure, elt("span", "x"));
704 var normal = node.getBoundingClientRect();
705 var fromRange = range(node, 0, 1).getBoundingClientRect();
706 return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
707 }
708
709 // Known modes, by name and by MIME
710 var modes = {}, mimeModes = {};
711
712 // Extra arguments are stored as the mode's dependencies, which is
713 // used by (legacy) mechanisms like loadmode.js to automatically
714 // load a mode. (Preferred mechanism is the require/define calls.)
715 function defineMode(name, mode) {
716 if (arguments.length > 2)
717 { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
718 modes[name] = mode;
719 }
720
721 function defineMIME(mime, spec) {
722 mimeModes[mime] = spec;
723 }
724
725 // Given a MIME type, a {name, ...options} config object, or a name
726 // string, return a mode config object.
727 function resolveMode(spec) {
728 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
729 spec = mimeModes[spec];
730 } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
731 var found = mimeModes[spec.name];
732 if (typeof found == "string") { found = {name: found}; }
733 spec = createObj(found, spec);
734 spec.name = found.name;
735 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
736 return resolveMode("application/xml")
737 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
738 return resolveMode("application/json")
739 }
740 if (typeof spec == "string") { return {name: spec} }
741 else { return spec || {name: "null"} }
742 }
743
744 // Given a mode spec (anything that resolveMode accepts), find and
745 // initialize an actual mode object.
746 function getMode(options, spec) {
747 spec = resolveMode(spec);
748 var mfactory = modes[spec.name];
749 if (!mfactory) { return getMode(options, "text/plain") }
750 var modeObj = mfactory(options, spec);
751 if (modeExtensions.hasOwnProperty(spec.name)) {
752 var exts = modeExtensions[spec.name];
753 for (var prop in exts) {
754 if (!exts.hasOwnProperty(prop)) { continue }
755 if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
756 modeObj[prop] = exts[prop];
757 }
758 }
759 modeObj.name = spec.name;
760 if (spec.helperType) { modeObj.helperType = spec.helperType; }
761 if (spec.modeProps) { for (var prop$1 in spec.modeProps)
762 { modeObj[prop$1] = spec.modeProps[prop$1]; } }
763
764 return modeObj
765 }
766
767 // This can be used to attach properties to mode objects from
768 // outside the actual mode definition.
769 var modeExtensions = {};
770 function extendMode(mode, properties) {
771 var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
772 copyObj(properties, exts);
773 }
774
775 function copyState(mode, state) {
776 if (state === true) { return state }
777 if (mode.copyState) { return mode.copyState(state) }
778 var nstate = {};
779 for (var n in state) {
780 var val = state[n];
781 if (val instanceof Array) { val = val.concat([]); }
782 nstate[n] = val;
783 }
784 return nstate
785 }
786
787 // Given a mode and a state (for that mode), find the inner mode and
788 // state at the position that the state refers to.
789 function innerMode(mode, state) {
790 var info;
791 while (mode.innerMode) {
792 info = mode.innerMode(state);
793 if (!info || info.mode == mode) { break }
794 state = info.state;
795 mode = info.mode;
796 }
797 return info || {mode: mode, state: state}
798 }
799
800 function startState(mode, a1, a2) {
801 return mode.startState ? mode.startState(a1, a2) : true
802 }
803
804 // STRING STREAM
805
806 // Fed to the mode parsers, provides helper functions to make
807 // parsers more succinct.
808
809 var StringStream = function(string, tabSize, lineOracle) {
810 this.pos = this.start = 0;
811 this.string = string;
812 this.tabSize = tabSize || 8;
813 this.lastColumnPos = this.lastColumnValue = 0;
814 this.lineStart = 0;
815 this.lineOracle = lineOracle;
816 };
817
818 StringStream.prototype.eol = function () {return this.pos >= this.string.length};
819 StringStream.prototype.sol = function () {return this.pos == this.lineStart};
820 StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
821 StringStream.prototype.next = function () {
822 if (this.pos < this.string.length)
823 { return this.string.charAt(this.pos++) }
824 };
825 StringStream.prototype.eat = function (match) {
826 var ch = this.string.charAt(this.pos);
827 var ok;
828 if (typeof match == "string") { ok = ch == match; }
829 else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
830 if (ok) {++this.pos; return ch}
831 };
832 StringStream.prototype.eatWhile = function (match) {
833 var start = this.pos;
834 while (this.eat(match)){}
835 return this.pos > start
836 };
837 StringStream.prototype.eatSpace = function () {
838 var this$1 = this;
839
840 var start = this.pos;
841 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }
842 return this.pos > start
843 };
844 StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
845 StringStream.prototype.skipTo = function (ch) {
846 var found = this.string.indexOf(ch, this.pos);
847 if (found > -1) {this.pos = found; return true}
848 };
849 StringStream.prototype.backUp = function (n) {this.pos -= n;};
850 StringStream.prototype.column = function () {
851 if (this.lastColumnPos < this.start) {
852 this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
853 this.lastColumnPos = this.start;
854 }
855 return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
856 };
857 StringStream.prototype.indentation = function () {
858 return countColumn(this.string, null, this.tabSize) -
859 (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
860 };
861 StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
862 if (typeof pattern == "string") {
863 var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
864 var substr = this.string.substr(this.pos, pattern.length);
865 if (cased(substr) == cased(pattern)) {
866 if (consume !== false) { this.pos += pattern.length; }
867 return true
868 }
869 } else {
870 var match = this.string.slice(this.pos).match(pattern);
871 if (match && match.index > 0) { return null }
872 if (match && consume !== false) { this.pos += match[0].length; }
873 return match
874 }
875 };
876 StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
877 StringStream.prototype.hideFirstChars = function (n, inner) {
878 this.lineStart += n;
879 try { return inner() }
880 finally { this.lineStart -= n; }
881 };
882 StringStream.prototype.lookAhead = function (n) {
883 var oracle = this.lineOracle;
884 return oracle && oracle.lookAhead(n)
885 };
886 StringStream.prototype.baseToken = function () {
887 var oracle = this.lineOracle;
888 return oracle && oracle.baseToken(this.pos)
889 };
890
891 // Find the line object corresponding to the given line number.
892 function getLine(doc, n) {
893 n -= doc.first;
894 if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
895 var chunk = doc;
896 while (!chunk.lines) {
897 for (var i = 0;; ++i) {
898 var child = chunk.children[i], sz = child.chunkSize();
899 if (n < sz) { chunk = child; break }
900 n -= sz;
901 }
902 }
903 return chunk.lines[n]
904 }
905
906 // Get the part of a document between two positions, as an array of
907 // strings.
908 function getBetween(doc, start, end) {
909 var out = [], n = start.line;
910 doc.iter(start.line, end.line + 1, function (line) {
911 var text = line.text;
912 if (n == end.line) { text = text.slice(0, end.ch); }
913 if (n == start.line) { text = text.slice(start.ch); }
914 out.push(text);
915 ++n;
916 });
917 return out
918 }
919 // Get the lines between from and to, as array of strings.
920 function getLines(doc, from, to) {
921 var out = [];
922 doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
923 return out
924 }
925
926 // Update the height of a line, propagating the height change
927 // upwards to parent nodes.
928 function updateLineHeight(line, height) {
929 var diff = height - line.height;
930 if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
931 }
932
933 // Given a line object, find its line number by walking up through
934 // its parent links.
935 function lineNo(line) {
936 if (line.parent == null) { return null }
937 var cur = line.parent, no = indexOf(cur.lines, line);
938 for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
939 for (var i = 0;; ++i) {
940 if (chunk.children[i] == cur) { break }
941 no += chunk.children[i].chunkSize();
942 }
943 }
944 return no + cur.first
945 }
946
947 // Find the line at the given vertical position, using the height
948 // information in the document tree.
949 function lineAtHeight(chunk, h) {
950 var n = chunk.first;
951 outer: do {
952 for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
953 var child = chunk.children[i$1], ch = child.height;
954 if (h < ch) { chunk = child; continue outer }
955 h -= ch;
956 n += child.chunkSize();
957 }
958 return n
959 } while (!chunk.lines)
960 var i = 0;
961 for (; i < chunk.lines.length; ++i) {
962 var line = chunk.lines[i], lh = line.height;
963 if (h < lh) { break }
964 h -= lh;
965 }
966 return n + i
967 }
968
969 function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
970
971 function lineNumberFor(options, i) {
972 return String(options.lineNumberFormatter(i + options.firstLineNumber))
973 }
974
975 // A Pos instance represents a position within the text.
976 function Pos(line, ch, sticky) {
977 if ( sticky === void 0 ) sticky = null;
978
979 if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
980 this.line = line;
981 this.ch = ch;
982 this.sticky = sticky;
983 }
984
985 // Compare two positions, return 0 if they are the same, a negative
986 // number when a is less, and a positive number otherwise.
987 function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
988
989 function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
990
991 function copyPos(x) {return Pos(x.line, x.ch)}
992 function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
993 function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
994
995 // Most of the external API clips given positions to make sure they
996 // actually exist within the document.
997 function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
998 function clipPos(doc, pos) {
999 if (pos.line < doc.first) { return Pos(doc.first, 0) }
1000 var last = doc.first + doc.size - 1;
1001 if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
1002 return clipToLen(pos, getLine(doc, pos.line).text.length)
1003 }
1004 function clipToLen(pos, linelen) {
1005 var ch = pos.ch;
1006 if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
1007 else if (ch < 0) { return Pos(pos.line, 0) }
1008 else { return pos }
1009 }
1010 function clipPosArray(doc, array) {
1011 var out = [];
1012 for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
1013 return out
1014 }
1015
1016 var SavedContext = function(state, lookAhead) {
1017 this.state = state;
1018 this.lookAhead = lookAhead;
1019 };
1020
1021 var Context = function(doc, state, line, lookAhead) {
1022 this.state = state;
1023 this.doc = doc;
1024 this.line = line;
1025 this.maxLookAhead = lookAhead || 0;
1026 this.baseTokens = null;
1027 this.baseTokenPos = 1;
1028 };
1029
1030 Context.prototype.lookAhead = function (n) {
1031 var line = this.doc.getLine(this.line + n);
1032 if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
1033 return line
1034 };
1035
1036 Context.prototype.baseToken = function (n) {
1037 var this$1 = this;
1038
1039 if (!this.baseTokens) { return null }
1040 while (this.baseTokens[this.baseTokenPos] <= n)
1041 { this$1.baseTokenPos += 2; }
1042 var type = this.baseTokens[this.baseTokenPos + 1];
1043 return {type: type && type.replace(/( |^)overlay .*/, ""),
1044 size: this.baseTokens[this.baseTokenPos] - n}
1045 };
1046
1047 Context.prototype.nextLine = function () {
1048 this.line++;
1049 if (this.maxLookAhead > 0) { this.maxLookAhead--; }
1050 };
1051
1052 Context.fromSaved = function (doc, saved, line) {
1053 if (saved instanceof SavedContext)
1054 { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
1055 else
1056 { return new Context(doc, copyState(doc.mode, saved), line) }
1057 };
1058
1059 Context.prototype.save = function (copy) {
1060 var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
1061 return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
1062 };
1063
1064
1065 // Compute a style array (an array starting with a mode generation
1066 // -- for invalidation -- followed by pairs of end positions and
1067 // style strings), which is used to highlight the tokens on the
1068 // line.
1069 function highlightLine(cm, line, context, forceToEnd) {
1070 // A styles array always starts with a number identifying the
1071 // mode/overlays that it is based on (for easy invalidation).
1072 var st = [cm.state.modeGen], lineClasses = {};
1073 // Compute the base array of styles
1074 runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
1075 lineClasses, forceToEnd);
1076 var state = context.state;
1077
1078 // Run overlays, adjust style array.
1079 var loop = function ( o ) {
1080 context.baseTokens = st;
1081 var overlay = cm.state.overlays[o], i = 1, at = 0;
1082 context.state = true;
1083 runMode(cm, line.text, overlay.mode, context, function (end, style) {
1084 var start = i;
1085 // Ensure there's a token end at the current position, and that i points at it
1086 while (at < end) {
1087 var i_end = st[i];
1088 if (i_end > end)
1089 { st.splice(i, 1, end, st[i+1], i_end); }
1090 i += 2;
1091 at = Math.min(end, i_end);
1092 }
1093 if (!style) { return }
1094 if (overlay.opaque) {
1095 st.splice(start, i - start, end, "overlay " + style);
1096 i = start + 2;
1097 } else {
1098 for (; start < i; start += 2) {
1099 var cur = st[start+1];
1100 st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
1101 }
1102 }
1103 }, lineClasses);
1104 context.state = state;
1105 context.baseTokens = null;
1106 context.baseTokenPos = 1;
1107 };
1108
1109 for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
1110
1111 return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
1112 }
1113
1114 function getLineStyles(cm, line, updateFrontier) {
1115 if (!line.styles || line.styles[0] != cm.state.modeGen) {
1116 var context = getContextBefore(cm, lineNo(line));
1117 var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
1118 var result = highlightLine(cm, line, context);
1119 if (resetState) { context.state = resetState; }
1120 line.stateAfter = context.save(!resetState);
1121 line.styles = result.styles;
1122 if (result.classes) { line.styleClasses = result.classes; }
1123 else if (line.styleClasses) { line.styleClasses = null; }
1124 if (updateFrontier === cm.doc.highlightFrontier)
1125 { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
1126 }
1127 return line.styles
1128 }
1129
1130 function getContextBefore(cm, n, precise) {
1131 var doc = cm.doc, display = cm.display;
1132 if (!doc.mode.startState) { return new Context(doc, true, n) }
1133 var start = findStartLine(cm, n, precise);
1134 var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
1135 var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
1136
1137 doc.iter(start, n, function (line) {
1138 processLine(cm, line.text, context);
1139 var pos = context.line;
1140 line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
1141 context.nextLine();
1142 });
1143 if (precise) { doc.modeFrontier = context.line; }
1144 return context
1145 }
1146
1147 // Lightweight form of highlight -- proceed over this line and
1148 // update state, but don't save a style array. Used for lines that
1149 // aren't currently visible.
1150 function processLine(cm, text, context, startAt) {
1151 var mode = cm.doc.mode;
1152 var stream = new StringStream(text, cm.options.tabSize, context);
1153 stream.start = stream.pos = startAt || 0;
1154 if (text == "") { callBlankLine(mode, context.state); }
1155 while (!stream.eol()) {
1156 readToken(mode, stream, context.state);
1157 stream.start = stream.pos;
1158 }
1159 }
1160
1161 function callBlankLine(mode, state) {
1162 if (mode.blankLine) { return mode.blankLine(state) }
1163 if (!mode.innerMode) { return }
1164 var inner = innerMode(mode, state);
1165 if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
1166 }
1167
1168 function readToken(mode, stream, state, inner) {
1169 for (var i = 0; i < 10; i++) {
1170 if (inner) { inner[0] = innerMode(mode, state).mode; }
1171 var style = mode.token(stream, state);
1172 if (stream.pos > stream.start) { return style }
1173 }
1174 throw new Error("Mode " + mode.name + " failed to advance stream.")
1175 }
1176
1177 var Token = function(stream, type, state) {
1178 this.start = stream.start; this.end = stream.pos;
1179 this.string = stream.current();
1180 this.type = type || null;
1181 this.state = state;
1182 };
1183
1184 // Utility for getTokenAt and getLineTokens
1185 function takeToken(cm, pos, precise, asArray) {
1186 var doc = cm.doc, mode = doc.mode, style;
1187 pos = clipPos(doc, pos);
1188 var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
1189 var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
1190 if (asArray) { tokens = []; }
1191 while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
1192 stream.start = stream.pos;
1193 style = readToken(mode, stream, context.state);
1194 if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
1195 }
1196 return asArray ? tokens : new Token(stream, style, context.state)
1197 }
1198
1199 function extractLineClasses(type, output) {
1200 if (type) { for (;;) {
1201 var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
1202 if (!lineClass) { break }
1203 type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
1204 var prop = lineClass[1] ? "bgClass" : "textClass";
1205 if (output[prop] == null)
1206 { output[prop] = lineClass[2]; }
1207 else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
1208 { output[prop] += " " + lineClass[2]; }
1209 } }
1210 return type
1211 }
1212
1213 // Run the given mode's parser over a line, calling f for each token.
1214 function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
1215 var flattenSpans = mode.flattenSpans;
1216 if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
1217 var curStart = 0, curStyle = null;
1218 var stream = new StringStream(text, cm.options.tabSize, context), style;
1219 var inner = cm.options.addModeClass && [null];
1220 if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
1221 while (!stream.eol()) {
1222 if (stream.pos > cm.options.maxHighlightLength) {
1223 flattenSpans = false;
1224 if (forceToEnd) { processLine(cm, text, context, stream.pos); }
1225 stream.pos = text.length;
1226 style = null;
1227 } else {
1228 style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
1229 }
1230 if (inner) {
1231 var mName = inner[0].name;
1232 if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
1233 }
1234 if (!flattenSpans || curStyle != style) {
1235 while (curStart < stream.start) {
1236 curStart = Math.min(stream.start, curStart + 5000);
1237 f(curStart, curStyle);
1238 }
1239 curStyle = style;
1240 }
1241 stream.start = stream.pos;
1242 }
1243 while (curStart < stream.pos) {
1244 // Webkit seems to refuse to render text nodes longer than 57444
1245 // characters, and returns inaccurate measurements in nodes
1246 // starting around 5000 chars.
1247 var pos = Math.min(stream.pos, curStart + 5000);
1248 f(pos, curStyle);
1249 curStart = pos;
1250 }
1251 }
1252
1253 // Finds the line to start with when starting a parse. Tries to
1254 // find a line with a stateAfter, so that it can start with a
1255 // valid state. If that fails, it returns the line with the
1256 // smallest indentation, which tends to need the least context to
1257 // parse correctly.
1258 function findStartLine(cm, n, precise) {
1259 var minindent, minline, doc = cm.doc;
1260 var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
1261 for (var search = n; search > lim; --search) {
1262 if (search <= doc.first) { return doc.first }
1263 var line = getLine(doc, search - 1), after = line.stateAfter;
1264 if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
1265 { return search }
1266 var indented = countColumn(line.text, null, cm.options.tabSize);
1267 if (minline == null || minindent > indented) {
1268 minline = search - 1;
1269 minindent = indented;
1270 }
1271 }
1272 return minline
1273 }
1274
1275 function retreatFrontier(doc, n) {
1276 doc.modeFrontier = Math.min(doc.modeFrontier, n);
1277 if (doc.highlightFrontier < n - 10) { return }
1278 var start = doc.first;
1279 for (var line = n - 1; line > start; line--) {
1280 var saved = getLine(doc, line).stateAfter;
1281 // change is on 3
1282 // state on line 1 looked ahead 2 -- so saw 3
1283 // test 1 + 2 < 3 should cover this
1284 if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
1285 start = line + 1;
1286 break
1287 }
1288 }
1289 doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
1290 }
1291
53 // Optimize some code when these features are not used.
1292 // Optimize some code when these features are not used.
54 var sawReadOnlySpans = false, sawCollapsedSpans = false;
1293 var sawReadOnlySpans = false, sawCollapsedSpans = false;
55
1294
56 // EDITOR CONSTRUCTOR
1295 function seeReadOnlySpans() {
57
1296 sawReadOnlySpans = true;
58 // A CodeMirror instance represents an editor. This is the object
1297 }
59 // that user code is usually dealing with.
1298
60
1299 function seeCollapsedSpans() {
61 function CodeMirror(place, options) {
1300 sawCollapsedSpans = true;
62 if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
1301 }
63
1302
64 this.options = options = options ? copyObj(options) : {};
1303 // TEXTMARKER SPANS
65 // Determine effective options based on given values and defaults.
1304
66 copyObj(defaults, options, false);
1305 function MarkedSpan(marker, from, to) {
67 setGuttersForLineNumbers(options);
1306 this.marker = marker;
68
1307 this.from = from; this.to = to;
69 var doc = options.value;
1308 }
70 if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator);
1309
71 this.doc = doc;
1310 // Search an array of spans for a span matching the given marker.
72
1311 function getMarkedSpanFor(spans, marker) {
73 var input = new CodeMirror.inputStyles[options.inputStyle](this);
1312 if (spans) { for (var i = 0; i < spans.length; ++i) {
74 var display = this.display = new Display(place, doc, input);
1313 var span = spans[i];
75 display.wrapper.CodeMirror = this;
1314 if (span.marker == marker) { return span }
76 updateGutters(this);
1315 } }
77 themeChanged(this);
1316 }
78 if (options.lineWrapping)
1317 // Remove a span from an array, returning undefined if no spans are
79 this.display.wrapper.className += " CodeMirror-wrap";
1318 // left (we don't store arrays for lines without spans).
80 if (options.autofocus && !mobile) display.input.focus();
1319 function removeMarkedSpan(spans, span) {
81 initScrollbars(this);
1320 var r;
82
1321 for (var i = 0; i < spans.length; ++i)
83 this.state = {
1322 { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
84 keyMaps: [], // stores maps added by addKeyMap
1323 return r
85 overlays: [], // highlighting overlays, as added by addOverlay
1324 }
86 modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
1325 // Add a span to a line.
87 overwrite: false,
1326 function addMarkedSpan(line, span) {
88 delayingBlurEvent: false,
1327 line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
89 focused: false,
1328 span.marker.attachLine(line);
90 suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
1329 }
91 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
1330
92 selectingText: false,
1331 // Used for the algorithm that adjusts markers for a change in the
93 draggingText: false,
1332 // document. These functions cut an array of spans at a given
94 highlight: new Delayed(), // stores highlight worker timeout
1333 // character position, returning an array of remaining chunks (or
95 keySeq: null, // Unfinished key sequence
1334 // undefined if nothing remains).
96 specialChars: null
1335 function markedSpansBefore(old, startCh, isInsert) {
97 };
1336 var nw;
98
1337 if (old) { for (var i = 0; i < old.length; ++i) {
99 var cm = this;
1338 var span = old[i], marker = span.marker;
100
1339 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
101 // Override magic textarea content restore that IE sometimes does
1340 if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
102 // on our hidden textarea on reload
1341 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
103 if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20);
1342 ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
104
1343 }
105 registerEventHandlers(this);
1344 } }
106 ensureGlobalHandlers();
1345 return nw
107
1346 }
1347 function markedSpansAfter(old, endCh, isInsert) {
1348 var nw;
1349 if (old) { for (var i = 0; i < old.length; ++i) {
1350 var span = old[i], marker = span.marker;
1351 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
1352 if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
1353 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
1354 ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
1355 span.to == null ? null : span.to - endCh));
1356 }
1357 } }
1358 return nw
1359 }
1360
1361 // Given a change object, compute the new set of marker spans that
1362 // cover the line in which the change took place. Removes spans
1363 // entirely within the change, reconnects spans belonging to the
1364 // same marker that appear on both sides of the change, and cuts off
1365 // spans partially within the change. Returns an array of span
1366 // arrays with one element for each line in (after) the change.
1367 function stretchSpansOverChange(doc, change) {
1368 if (change.full) { return null }
1369 var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
1370 var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
1371 if (!oldFirst && !oldLast) { return null }
1372
1373 var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
1374 // Get the spans that 'stick out' on both sides
1375 var first = markedSpansBefore(oldFirst, startCh, isInsert);
1376 var last = markedSpansAfter(oldLast, endCh, isInsert);
1377
1378 // Next, merge those two ends
1379 var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
1380 if (first) {
1381 // Fix up .to properties of first
1382 for (var i = 0; i < first.length; ++i) {
1383 var span = first[i];
1384 if (span.to == null) {
1385 var found = getMarkedSpanFor(last, span.marker);
1386 if (!found) { span.to = startCh; }
1387 else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
1388 }
1389 }
1390 }
1391 if (last) {
1392 // Fix up .from in last (or move them into first in case of sameLine)
1393 for (var i$1 = 0; i$1 < last.length; ++i$1) {
1394 var span$1 = last[i$1];
1395 if (span$1.to != null) { span$1.to += offset; }
1396 if (span$1.from == null) {
1397 var found$1 = getMarkedSpanFor(first, span$1.marker);
1398 if (!found$1) {
1399 span$1.from = offset;
1400 if (sameLine) { (first || (first = [])).push(span$1); }
1401 }
1402 } else {
1403 span$1.from += offset;
1404 if (sameLine) { (first || (first = [])).push(span$1); }
1405 }
1406 }
1407 }
1408 // Make sure we didn't create any zero-length spans
1409 if (first) { first = clearEmptySpans(first); }
1410 if (last && last != first) { last = clearEmptySpans(last); }
1411
1412 var newMarkers = [first];
1413 if (!sameLine) {
1414 // Fill gap with whole-line-spans
1415 var gap = change.text.length - 2, gapMarkers;
1416 if (gap > 0 && first)
1417 { for (var i$2 = 0; i$2 < first.length; ++i$2)
1418 { if (first[i$2].to == null)
1419 { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
1420 for (var i$3 = 0; i$3 < gap; ++i$3)
1421 { newMarkers.push(gapMarkers); }
1422 newMarkers.push(last);
1423 }
1424 return newMarkers
1425 }
1426
1427 // Remove spans that are empty and don't have a clearWhenEmpty
1428 // option of false.
1429 function clearEmptySpans(spans) {
1430 for (var i = 0; i < spans.length; ++i) {
1431 var span = spans[i];
1432 if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
1433 { spans.splice(i--, 1); }
1434 }
1435 if (!spans.length) { return null }
1436 return spans
1437 }
1438
1439 // Used to 'clip' out readOnly ranges when making a change.
1440 function removeReadOnlyRanges(doc, from, to) {
1441 var markers = null;
1442 doc.iter(from.line, to.line + 1, function (line) {
1443 if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
1444 var mark = line.markedSpans[i].marker;
1445 if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
1446 { (markers || (markers = [])).push(mark); }
1447 } }
1448 });
1449 if (!markers) { return null }
1450 var parts = [{from: from, to: to}];
1451 for (var i = 0; i < markers.length; ++i) {
1452 var mk = markers[i], m = mk.find(0);
1453 for (var j = 0; j < parts.length; ++j) {
1454 var p = parts[j];
1455 if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
1456 var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
1457 if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
1458 { newParts.push({from: p.from, to: m.from}); }
1459 if (dto > 0 || !mk.inclusiveRight && !dto)
1460 { newParts.push({from: m.to, to: p.to}); }
1461 parts.splice.apply(parts, newParts);
1462 j += newParts.length - 3;
1463 }
1464 }
1465 return parts
1466 }
1467
1468 // Connect or disconnect spans from a line.
1469 function detachMarkedSpans(line) {
1470 var spans = line.markedSpans;
1471 if (!spans) { return }
1472 for (var i = 0; i < spans.length; ++i)
1473 { spans[i].marker.detachLine(line); }
1474 line.markedSpans = null;
1475 }
1476 function attachMarkedSpans(line, spans) {
1477 if (!spans) { return }
1478 for (var i = 0; i < spans.length; ++i)
1479 { spans[i].marker.attachLine(line); }
1480 line.markedSpans = spans;
1481 }
1482
1483 // Helpers used when computing which overlapping collapsed span
1484 // counts as the larger one.
1485 function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
1486 function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
1487
1488 // Returns a number indicating which of two overlapping collapsed
1489 // spans is larger (and thus includes the other). Falls back to
1490 // comparing ids when the spans cover exactly the same range.
1491 function compareCollapsedMarkers(a, b) {
1492 var lenDiff = a.lines.length - b.lines.length;
1493 if (lenDiff != 0) { return lenDiff }
1494 var aPos = a.find(), bPos = b.find();
1495 var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
1496 if (fromCmp) { return -fromCmp }
1497 var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
1498 if (toCmp) { return toCmp }
1499 return b.id - a.id
1500 }
1501
1502 // Find out whether a line ends or starts in a collapsed span. If
1503 // so, return the marker for that span.
1504 function collapsedSpanAtSide(line, start) {
1505 var sps = sawCollapsedSpans && line.markedSpans, found;
1506 if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
1507 sp = sps[i];
1508 if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
1509 (!found || compareCollapsedMarkers(found, sp.marker) < 0))
1510 { found = sp.marker; }
1511 } }
1512 return found
1513 }
1514 function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
1515 function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
1516
1517 function collapsedSpanAround(line, ch) {
1518 var sps = sawCollapsedSpans && line.markedSpans, found;
1519 if (sps) { for (var i = 0; i < sps.length; ++i) {
1520 var sp = sps[i];
1521 if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
1522 (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }
1523 } }
1524 return found
1525 }
1526
1527 // Test whether there exists a collapsed span that partially
1528 // overlaps (covers the start or end, but not both) of a new span.
1529 // Such overlap is not allowed.
1530 function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
1531 var line = getLine(doc, lineNo$$1);
1532 var sps = sawCollapsedSpans && line.markedSpans;
1533 if (sps) { for (var i = 0; i < sps.length; ++i) {
1534 var sp = sps[i];
1535 if (!sp.marker.collapsed) { continue }
1536 var found = sp.marker.find(0);
1537 var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
1538 var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
1539 if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
1540 if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
1541 fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
1542 { return true }
1543 } }
1544 }
1545
1546 // A visual line is a line as drawn on the screen. Folding, for
1547 // example, can cause multiple logical lines to appear on the same
1548 // visual line. This finds the start of the visual line that the
1549 // given line is part of (usually that is the line itself).
1550 function visualLine(line) {
1551 var merged;
1552 while (merged = collapsedSpanAtStart(line))
1553 { line = merged.find(-1, true).line; }
1554 return line
1555 }
1556
1557 function visualLineEnd(line) {
1558 var merged;
1559 while (merged = collapsedSpanAtEnd(line))
1560 { line = merged.find(1, true).line; }
1561 return line
1562 }
1563
1564 // Returns an array of logical lines that continue the visual line
1565 // started by the argument, or undefined if there are no such lines.
1566 function visualLineContinued(line) {
1567 var merged, lines;
1568 while (merged = collapsedSpanAtEnd(line)) {
1569 line = merged.find(1, true).line
1570 ;(lines || (lines = [])).push(line);
1571 }
1572 return lines
1573 }
1574
1575 // Get the line number of the start of the visual line that the
1576 // given line number is part of.
1577 function visualLineNo(doc, lineN) {
1578 var line = getLine(doc, lineN), vis = visualLine(line);
1579 if (line == vis) { return lineN }
1580 return lineNo(vis)
1581 }
1582
1583 // Get the line number of the start of the next visual line after
1584 // the given line.
1585 function visualLineEndNo(doc, lineN) {
1586 if (lineN > doc.lastLine()) { return lineN }
1587 var line = getLine(doc, lineN), merged;
1588 if (!lineIsHidden(doc, line)) { return lineN }
1589 while (merged = collapsedSpanAtEnd(line))
1590 { line = merged.find(1, true).line; }
1591 return lineNo(line) + 1
1592 }
1593
1594 // Compute whether a line is hidden. Lines count as hidden when they
1595 // are part of a visual line that starts with another line, or when
1596 // they are entirely covered by collapsed, non-widget span.
1597 function lineIsHidden(doc, line) {
1598 var sps = sawCollapsedSpans && line.markedSpans;
1599 if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
1600 sp = sps[i];
1601 if (!sp.marker.collapsed) { continue }
1602 if (sp.from == null) { return true }
1603 if (sp.marker.widgetNode) { continue }
1604 if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
1605 { return true }
1606 } }
1607 }
1608 function lineIsHiddenInner(doc, line, span) {
1609 if (span.to == null) {
1610 var end = span.marker.find(1, true);
1611 return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
1612 }
1613 if (span.marker.inclusiveRight && span.to == line.text.length)
1614 { return true }
1615 for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
1616 sp = line.markedSpans[i];
1617 if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
1618 (sp.to == null || sp.to != span.from) &&
1619 (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
1620 lineIsHiddenInner(doc, line, sp)) { return true }
1621 }
1622 }
1623
1624 // Find the height above the given line.
1625 function heightAtLine(lineObj) {
1626 lineObj = visualLine(lineObj);
1627
1628 var h = 0, chunk = lineObj.parent;
1629 for (var i = 0; i < chunk.lines.length; ++i) {
1630 var line = chunk.lines[i];
1631 if (line == lineObj) { break }
1632 else { h += line.height; }
1633 }
1634 for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
1635 for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
1636 var cur = p.children[i$1];
1637 if (cur == chunk) { break }
1638 else { h += cur.height; }
1639 }
1640 }
1641 return h
1642 }
1643
1644 // Compute the character length of a line, taking into account
1645 // collapsed ranges (see markText) that might hide parts, and join
1646 // other lines onto it.
1647 function lineLength(line) {
1648 if (line.height == 0) { return 0 }
1649 var len = line.text.length, merged, cur = line;
1650 while (merged = collapsedSpanAtStart(cur)) {
1651 var found = merged.find(0, true);
1652 cur = found.from.line;
1653 len += found.from.ch - found.to.ch;
1654 }
1655 cur = line;
1656 while (merged = collapsedSpanAtEnd(cur)) {
1657 var found$1 = merged.find(0, true);
1658 len -= cur.text.length - found$1.from.ch;
1659 cur = found$1.to.line;
1660 len += cur.text.length - found$1.to.ch;
1661 }
1662 return len
1663 }
1664
1665 // Find the longest line in the document.
1666 function findMaxLine(cm) {
1667 var d = cm.display, doc = cm.doc;
1668 d.maxLine = getLine(doc, doc.first);
1669 d.maxLineLength = lineLength(d.maxLine);
1670 d.maxLineChanged = true;
1671 doc.iter(function (line) {
1672 var len = lineLength(line);
1673 if (len > d.maxLineLength) {
1674 d.maxLineLength = len;
1675 d.maxLine = line;
1676 }
1677 });
1678 }
1679
1680 // LINE DATA STRUCTURE
1681
1682 // Line objects. These hold state related to a line, including
1683 // highlighting info (the styles array).
1684 var Line = function(text, markedSpans, estimateHeight) {
1685 this.text = text;
1686 attachMarkedSpans(this, markedSpans);
1687 this.height = estimateHeight ? estimateHeight(this) : 1;
1688 };
1689
1690 Line.prototype.lineNo = function () { return lineNo(this) };
1691 eventMixin(Line);
1692
1693 // Change the content (text, markers) of a line. Automatically
1694 // invalidates cached information and tries to re-estimate the
1695 // line's height.
1696 function updateLine(line, text, markedSpans, estimateHeight) {
1697 line.text = text;
1698 if (line.stateAfter) { line.stateAfter = null; }
1699 if (line.styles) { line.styles = null; }
1700 if (line.order != null) { line.order = null; }
1701 detachMarkedSpans(line);
1702 attachMarkedSpans(line, markedSpans);
1703 var estHeight = estimateHeight ? estimateHeight(line) : 1;
1704 if (estHeight != line.height) { updateLineHeight(line, estHeight); }
1705 }
1706
1707 // Detach a line from the document tree and its markers.
1708 function cleanUpLine(line) {
1709 line.parent = null;
1710 detachMarkedSpans(line);
1711 }
1712
1713 // Convert a style as returned by a mode (either null, or a string
1714 // containing one or more styles) to a CSS style. This is cached,
1715 // and also looks for line-wide styles.
1716 var styleToClassCache = {}, styleToClassCacheWithMode = {};
1717 function interpretTokenStyle(style, options) {
1718 if (!style || /^\s*$/.test(style)) { return null }
1719 var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
1720 return cache[style] ||
1721 (cache[style] = style.replace(/\S+/g, "cm-$&"))
1722 }
1723
1724 // Render the DOM representation of the text of a line. Also builds
1725 // up a 'line map', which points at the DOM nodes that represent
1726 // specific stretches of text, and is used by the measuring code.
1727 // The returned object contains the DOM node, this map, and
1728 // information about line-wide styles that were set by the mode.
1729 function buildLineContent(cm, lineView) {
1730 // The padding-right forces the element to have a 'border', which
1731 // is needed on Webkit to be able to get line-level bounding
1732 // rectangles for it (in measureChar).
1733 var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
1734 var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
1735 col: 0, pos: 0, cm: cm,
1736 trailingSpace: false,
1737 splitSpaces: cm.getOption("lineWrapping")};
1738 lineView.measure = {};
1739
1740 // Iterate over the logical lines that make up this visual line.
1741 for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
1742 var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
1743 builder.pos = 0;
1744 builder.addToken = buildToken;
1745 // Optionally wire in some hacks into the token-rendering
1746 // algorithm, to deal with browser quirks.
1747 if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
1748 { builder.addToken = buildTokenBadBidi(builder.addToken, order); }
1749 builder.map = [];
1750 var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
1751 insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
1752 if (line.styleClasses) {
1753 if (line.styleClasses.bgClass)
1754 { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
1755 if (line.styleClasses.textClass)
1756 { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
1757 }
1758
1759 // Ensure at least a single node is present, for measuring.
1760 if (builder.map.length == 0)
1761 { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
1762
1763 // Store the map and a cache object for the current logical line
1764 if (i == 0) {
1765 lineView.measure.map = builder.map;
1766 lineView.measure.cache = {};
1767 } else {
1768 (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
1769 ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
1770 }
1771 }
1772
1773 // See issue #2901
1774 if (webkit) {
1775 var last = builder.content.lastChild;
1776 if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
1777 { builder.content.className = "cm-tab-wrap-hack"; }
1778 }
1779
1780 signal(cm, "renderLine", cm, lineView.line, builder.pre);
1781 if (builder.pre.className)
1782 { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
1783
1784 return builder
1785 }
1786
1787 function defaultSpecialCharPlaceholder(ch) {
1788 var token = elt("span", "\u2022", "cm-invalidchar");
1789 token.title = "\\u" + ch.charCodeAt(0).toString(16);
1790 token.setAttribute("aria-label", token.title);
1791 return token
1792 }
1793
1794 // Build up the DOM representation for a single token, and add it to
1795 // the line map. Takes care to render special characters separately.
1796 function buildToken(builder, text, style, startStyle, endStyle, css, attributes) {
1797 if (!text) { return }
1798 var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
1799 var special = builder.cm.state.specialChars, mustWrap = false;
1800 var content;
1801 if (!special.test(text)) {
1802 builder.col += text.length;
1803 content = document.createTextNode(displayText);
1804 builder.map.push(builder.pos, builder.pos + text.length, content);
1805 if (ie && ie_version < 9) { mustWrap = true; }
1806 builder.pos += text.length;
1807 } else {
1808 content = document.createDocumentFragment();
1809 var pos = 0;
1810 while (true) {
1811 special.lastIndex = pos;
1812 var m = special.exec(text);
1813 var skipped = m ? m.index - pos : text.length - pos;
1814 if (skipped) {
1815 var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
1816 if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
1817 else { content.appendChild(txt); }
1818 builder.map.push(builder.pos, builder.pos + skipped, txt);
1819 builder.col += skipped;
1820 builder.pos += skipped;
1821 }
1822 if (!m) { break }
1823 pos += skipped + 1;
1824 var txt$1 = (void 0);
1825 if (m[0] == "\t") {
1826 var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
1827 txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
1828 txt$1.setAttribute("role", "presentation");
1829 txt$1.setAttribute("cm-text", "\t");
1830 builder.col += tabWidth;
1831 } else if (m[0] == "\r" || m[0] == "\n") {
1832 txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
1833 txt$1.setAttribute("cm-text", m[0]);
1834 builder.col += 1;
1835 } else {
1836 txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
1837 txt$1.setAttribute("cm-text", m[0]);
1838 if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
1839 else { content.appendChild(txt$1); }
1840 builder.col += 1;
1841 }
1842 builder.map.push(builder.pos, builder.pos + 1, txt$1);
1843 builder.pos++;
1844 }
1845 }
1846 builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
1847 if (style || startStyle || endStyle || mustWrap || css) {
1848 var fullStyle = style || "";
1849 if (startStyle) { fullStyle += startStyle; }
1850 if (endStyle) { fullStyle += endStyle; }
1851 var token = elt("span", [content], fullStyle, css);
1852 if (attributes) {
1853 for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class")
1854 { token.setAttribute(attr, attributes[attr]); } }
1855 }
1856 return builder.content.appendChild(token)
1857 }
1858 builder.content.appendChild(content);
1859 }
1860
1861 // Change some spaces to NBSP to prevent the browser from collapsing
1862 // trailing spaces at the end of a line when rendering text (issue #1362).
1863 function splitSpaces(text, trailingBefore) {
1864 if (text.length > 1 && !/ /.test(text)) { return text }
1865 var spaceBefore = trailingBefore, result = "";
1866 for (var i = 0; i < text.length; i++) {
1867 var ch = text.charAt(i);
1868 if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
1869 { ch = "\u00a0"; }
1870 result += ch;
1871 spaceBefore = ch == " ";
1872 }
1873 return result
1874 }
1875
1876 // Work around nonsense dimensions being reported for stretches of
1877 // right-to-left text.
1878 function buildTokenBadBidi(inner, order) {
1879 return function (builder, text, style, startStyle, endStyle, css, attributes) {
1880 style = style ? style + " cm-force-border" : "cm-force-border";
1881 var start = builder.pos, end = start + text.length;
1882 for (;;) {
1883 // Find the part that overlaps with the start of this text
1884 var part = (void 0);
1885 for (var i = 0; i < order.length; i++) {
1886 part = order[i];
1887 if (part.to > start && part.from <= start) { break }
1888 }
1889 if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, css, attributes) }
1890 inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes);
1891 startStyle = null;
1892 text = text.slice(part.to - start);
1893 start = part.to;
1894 }
1895 }
1896 }
1897
1898 function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
1899 var widget = !ignoreWidget && marker.widgetNode;
1900 if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
1901 if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
1902 if (!widget)
1903 { widget = builder.content.appendChild(document.createElement("span")); }
1904 widget.setAttribute("cm-marker", marker.id);
1905 }
1906 if (widget) {
1907 builder.cm.display.input.setUneditable(widget);
1908 builder.content.appendChild(widget);
1909 }
1910 builder.pos += size;
1911 builder.trailingSpace = false;
1912 }
1913
1914 // Outputs a number of spans to make up a line, taking highlighting
1915 // and marked text into account.
1916 function insertLineContent(line, builder, styles) {
1917 var spans = line.markedSpans, allText = line.text, at = 0;
1918 if (!spans) {
1919 for (var i$1 = 1; i$1 < styles.length; i$1+=2)
1920 { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
1921 return
1922 }
1923
1924 var len = allText.length, pos = 0, i = 1, text = "", style, css;
1925 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes;
1926 for (;;) {
1927 if (nextChange == pos) { // Update current marker set
1928 spanStyle = spanEndStyle = spanStartStyle = css = "";
1929 attributes = null;
1930 collapsed = null; nextChange = Infinity;
1931 var foundBookmarks = [], endStyles = (void 0);
1932 for (var j = 0; j < spans.length; ++j) {
1933 var sp = spans[j], m = sp.marker;
1934 if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
1935 foundBookmarks.push(m);
1936 } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
1937 if (sp.to != null && sp.to != pos && nextChange > sp.to) {
1938 nextChange = sp.to;
1939 spanEndStyle = "";
1940 }
1941 if (m.className) { spanStyle += " " + m.className; }
1942 if (m.css) { css = (css ? css + ";" : "") + m.css; }
1943 if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
1944 if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
1945 // support for the old title property
1946 // https://github.com/codemirror/CodeMirror/pull/5673
1947 if (m.title) { (attributes || (attributes = {})).title = m.title; }
1948 if (m.attributes) {
1949 for (var attr in m.attributes)
1950 { (attributes || (attributes = {}))[attr] = m.attributes[attr]; }
1951 }
1952 if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
1953 { collapsed = sp; }
1954 } else if (sp.from > pos && nextChange > sp.from) {
1955 nextChange = sp.from;
1956 }
1957 }
1958 if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
1959 { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
1960
1961 if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
1962 { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
1963 if (collapsed && (collapsed.from || 0) == pos) {
1964 buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
1965 collapsed.marker, collapsed.from == null);
1966 if (collapsed.to == null) { return }
1967 if (collapsed.to == pos) { collapsed = false; }
1968 }
1969 }
1970 if (pos >= len) { break }
1971
1972 var upto = Math.min(len, nextChange);
1973 while (true) {
1974 if (text) {
1975 var end = pos + text.length;
1976 if (!collapsed) {
1977 var tokenText = end > upto ? text.slice(0, upto - pos) : text;
1978 builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
1979 spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", css, attributes);
1980 }
1981 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
1982 pos = end;
1983 spanStartStyle = "";
1984 }
1985 text = allText.slice(at, at = styles[i++]);
1986 style = interpretTokenStyle(styles[i++], builder.cm.options);
1987 }
1988 }
1989 }
1990
1991
1992 // These objects are used to represent the visible (currently drawn)
1993 // part of the document. A LineView may correspond to multiple
1994 // logical lines, if those are connected by collapsed ranges.
1995 function LineView(doc, line, lineN) {
1996 // The starting line
1997 this.line = line;
1998 // Continuing lines, if any
1999 this.rest = visualLineContinued(line);
2000 // Number of logical lines in this visual line
2001 this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
2002 this.node = this.text = null;
2003 this.hidden = lineIsHidden(doc, line);
2004 }
2005
2006 // Create a range of LineView objects for the given lines.
2007 function buildViewArray(cm, from, to) {
2008 var array = [], nextPos;
2009 for (var pos = from; pos < to; pos = nextPos) {
2010 var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
2011 nextPos = pos + view.size;
2012 array.push(view);
2013 }
2014 return array
2015 }
2016
2017 var operationGroup = null;
2018
2019 function pushOperation(op) {
2020 if (operationGroup) {
2021 operationGroup.ops.push(op);
2022 } else {
2023 op.ownsGroup = operationGroup = {
2024 ops: [op],
2025 delayedCallbacks: []
2026 };
2027 }
2028 }
2029
2030 function fireCallbacksForOps(group) {
2031 // Calls delayed callbacks and cursorActivity handlers until no
2032 // new ones appear
2033 var callbacks = group.delayedCallbacks, i = 0;
2034 do {
2035 for (; i < callbacks.length; i++)
2036 { callbacks[i].call(null); }
2037 for (var j = 0; j < group.ops.length; j++) {
2038 var op = group.ops[j];
2039 if (op.cursorActivityHandlers)
2040 { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
2041 { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
2042 }
2043 } while (i < callbacks.length)
2044 }
2045
2046 function finishOperation(op, endCb) {
2047 var group = op.ownsGroup;
2048 if (!group) { return }
2049
2050 try { fireCallbacksForOps(group); }
2051 finally {
2052 operationGroup = null;
2053 endCb(group);
2054 }
2055 }
2056
2057 var orphanDelayedCallbacks = null;
2058
2059 // Often, we want to signal events at a point where we are in the
2060 // middle of some work, but don't want the handler to start calling
2061 // other methods on the editor, which might be in an inconsistent
2062 // state or simply not expect any other events to happen.
2063 // signalLater looks whether there are any handlers, and schedules
2064 // them to be executed when the last operation ends, or, if no
2065 // operation is active, when a timeout fires.
2066 function signalLater(emitter, type /*, values...*/) {
2067 var arr = getHandlers(emitter, type);
2068 if (!arr.length) { return }
2069 var args = Array.prototype.slice.call(arguments, 2), list;
2070 if (operationGroup) {
2071 list = operationGroup.delayedCallbacks;
2072 } else if (orphanDelayedCallbacks) {
2073 list = orphanDelayedCallbacks;
2074 } else {
2075 list = orphanDelayedCallbacks = [];
2076 setTimeout(fireOrphanDelayed, 0);
2077 }
2078 var loop = function ( i ) {
2079 list.push(function () { return arr[i].apply(null, args); });
2080 };
2081
2082 for (var i = 0; i < arr.length; ++i)
2083 loop( i );
2084 }
2085
2086 function fireOrphanDelayed() {
2087 var delayed = orphanDelayedCallbacks;
2088 orphanDelayedCallbacks = null;
2089 for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
2090 }
2091
2092 // When an aspect of a line changes, a string is added to
2093 // lineView.changes. This updates the relevant part of the line's
2094 // DOM structure.
2095 function updateLineForChanges(cm, lineView, lineN, dims) {
2096 for (var j = 0; j < lineView.changes.length; j++) {
2097 var type = lineView.changes[j];
2098 if (type == "text") { updateLineText(cm, lineView); }
2099 else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
2100 else if (type == "class") { updateLineClasses(cm, lineView); }
2101 else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
2102 }
2103 lineView.changes = null;
2104 }
2105
2106 // Lines with gutter elements, widgets or a background class need to
2107 // be wrapped, and have the extra elements added to the wrapper div
2108 function ensureLineWrapped(lineView) {
2109 if (lineView.node == lineView.text) {
2110 lineView.node = elt("div", null, null, "position: relative");
2111 if (lineView.text.parentNode)
2112 { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
2113 lineView.node.appendChild(lineView.text);
2114 if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
2115 }
2116 return lineView.node
2117 }
2118
2119 function updateLineBackground(cm, lineView) {
2120 var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
2121 if (cls) { cls += " CodeMirror-linebackground"; }
2122 if (lineView.background) {
2123 if (cls) { lineView.background.className = cls; }
2124 else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
2125 } else if (cls) {
2126 var wrap = ensureLineWrapped(lineView);
2127 lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
2128 cm.display.input.setUneditable(lineView.background);
2129 }
2130 }
2131
2132 // Wrapper around buildLineContent which will reuse the structure
2133 // in display.externalMeasured when possible.
2134 function getLineContent(cm, lineView) {
2135 var ext = cm.display.externalMeasured;
2136 if (ext && ext.line == lineView.line) {
2137 cm.display.externalMeasured = null;
2138 lineView.measure = ext.measure;
2139 return ext.built
2140 }
2141 return buildLineContent(cm, lineView)
2142 }
2143
2144 // Redraw the line's text. Interacts with the background and text
2145 // classes because the mode may output tokens that influence these
2146 // classes.
2147 function updateLineText(cm, lineView) {
2148 var cls = lineView.text.className;
2149 var built = getLineContent(cm, lineView);
2150 if (lineView.text == lineView.node) { lineView.node = built.pre; }
2151 lineView.text.parentNode.replaceChild(built.pre, lineView.text);
2152 lineView.text = built.pre;
2153 if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
2154 lineView.bgClass = built.bgClass;
2155 lineView.textClass = built.textClass;
2156 updateLineClasses(cm, lineView);
2157 } else if (cls) {
2158 lineView.text.className = cls;
2159 }
2160 }
2161
2162 function updateLineClasses(cm, lineView) {
2163 updateLineBackground(cm, lineView);
2164 if (lineView.line.wrapClass)
2165 { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
2166 else if (lineView.node != lineView.text)
2167 { lineView.node.className = ""; }
2168 var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
2169 lineView.text.className = textClass || "";
2170 }
2171
2172 function updateLineGutter(cm, lineView, lineN, dims) {
2173 if (lineView.gutter) {
2174 lineView.node.removeChild(lineView.gutter);
2175 lineView.gutter = null;
2176 }
2177 if (lineView.gutterBackground) {
2178 lineView.node.removeChild(lineView.gutterBackground);
2179 lineView.gutterBackground = null;
2180 }
2181 if (lineView.line.gutterClass) {
2182 var wrap = ensureLineWrapped(lineView);
2183 lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
2184 ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
2185 cm.display.input.setUneditable(lineView.gutterBackground);
2186 wrap.insertBefore(lineView.gutterBackground, lineView.text);
2187 }
2188 var markers = lineView.line.gutterMarkers;
2189 if (cm.options.lineNumbers || markers) {
2190 var wrap$1 = ensureLineWrapped(lineView);
2191 var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
2192 cm.display.input.setUneditable(gutterWrap);
2193 wrap$1.insertBefore(gutterWrap, lineView.text);
2194 if (lineView.line.gutterClass)
2195 { gutterWrap.className += " " + lineView.line.gutterClass; }
2196 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
2197 { lineView.lineNumber = gutterWrap.appendChild(
2198 elt("div", lineNumberFor(cm.options, lineN),
2199 "CodeMirror-linenumber CodeMirror-gutter-elt",
2200 ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
2201 if (markers) { for (var k = 0; k < cm.display.gutterSpecs.length; ++k) {
2202 var id = cm.display.gutterSpecs[k].className, found = markers.hasOwnProperty(id) && markers[id];
2203 if (found)
2204 { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
2205 ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
2206 } }
2207 }
2208 }
2209
2210 function updateLineWidgets(cm, lineView, dims) {
2211 if (lineView.alignable) { lineView.alignable = null; }
2212 for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
2213 next = node.nextSibling;
2214 if (node.className == "CodeMirror-linewidget")
2215 { lineView.node.removeChild(node); }
2216 }
2217 insertLineWidgets(cm, lineView, dims);
2218 }
2219
2220 // Build a line's DOM representation from scratch
2221 function buildLineElement(cm, lineView, lineN, dims) {
2222 var built = getLineContent(cm, lineView);
2223 lineView.text = lineView.node = built.pre;
2224 if (built.bgClass) { lineView.bgClass = built.bgClass; }
2225 if (built.textClass) { lineView.textClass = built.textClass; }
2226
2227 updateLineClasses(cm, lineView);
2228 updateLineGutter(cm, lineView, lineN, dims);
2229 insertLineWidgets(cm, lineView, dims);
2230 return lineView.node
2231 }
2232
2233 // A lineView may contain multiple logical lines (when merged by
2234 // collapsed spans). The widgets for all of them need to be drawn.
2235 function insertLineWidgets(cm, lineView, dims) {
2236 insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
2237 if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
2238 { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
2239 }
2240
2241 function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
2242 if (!line.widgets) { return }
2243 var wrap = ensureLineWrapped(lineView);
2244 for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
2245 var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
2246 if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
2247 positionLineWidget(widget, node, lineView, dims);
2248 cm.display.input.setUneditable(node);
2249 if (allowAbove && widget.above)
2250 { wrap.insertBefore(node, lineView.gutter || lineView.text); }
2251 else
2252 { wrap.appendChild(node); }
2253 signalLater(widget, "redraw");
2254 }
2255 }
2256
2257 function positionLineWidget(widget, node, lineView, dims) {
2258 if (widget.noHScroll) {
2259 (lineView.alignable || (lineView.alignable = [])).push(node);
2260 var width = dims.wrapperWidth;
2261 node.style.left = dims.fixedPos + "px";
2262 if (!widget.coverGutter) {
2263 width -= dims.gutterTotalWidth;
2264 node.style.paddingLeft = dims.gutterTotalWidth + "px";
2265 }
2266 node.style.width = width + "px";
2267 }
2268 if (widget.coverGutter) {
2269 node.style.zIndex = 5;
2270 node.style.position = "relative";
2271 if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
2272 }
2273 }
2274
2275 function widgetHeight(widget) {
2276 if (widget.height != null) { return widget.height }
2277 var cm = widget.doc.cm;
2278 if (!cm) { return 0 }
2279 if (!contains(document.body, widget.node)) {
2280 var parentStyle = "position: relative;";
2281 if (widget.coverGutter)
2282 { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
2283 if (widget.noHScroll)
2284 { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
2285 removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
2286 }
2287 return widget.height = widget.node.parentNode.offsetHeight
2288 }
2289
2290 // Return true when the given mouse event happened in a widget
2291 function eventInWidget(display, e) {
2292 for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
2293 if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
2294 (n.parentNode == display.sizer && n != display.mover))
2295 { return true }
2296 }
2297 }
2298
2299 // POSITION MEASUREMENT
2300
2301 function paddingTop(display) {return display.lineSpace.offsetTop}
2302 function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
2303 function paddingH(display) {
2304 if (display.cachedPaddingH) { return display.cachedPaddingH }
2305 var e = removeChildrenAndAdd(display.measure, elt("pre", "x", "CodeMirror-line-like"));
2306 var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
2307 var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
2308 if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
2309 return data
2310 }
2311
2312 function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
2313 function displayWidth(cm) {
2314 return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
2315 }
2316 function displayHeight(cm) {
2317 return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
2318 }
2319
2320 // Ensure the lineView.wrapping.heights array is populated. This is
2321 // an array of bottom offsets for the lines that make up a drawn
2322 // line. When lineWrapping is on, there might be more than one
2323 // height.
2324 function ensureLineHeights(cm, lineView, rect) {
2325 var wrapping = cm.options.lineWrapping;
2326 var curWidth = wrapping && displayWidth(cm);
2327 if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
2328 var heights = lineView.measure.heights = [];
2329 if (wrapping) {
2330 lineView.measure.width = curWidth;
2331 var rects = lineView.text.firstChild.getClientRects();
2332 for (var i = 0; i < rects.length - 1; i++) {
2333 var cur = rects[i], next = rects[i + 1];
2334 if (Math.abs(cur.bottom - next.bottom) > 2)
2335 { heights.push((cur.bottom + next.top) / 2 - rect.top); }
2336 }
2337 }
2338 heights.push(rect.bottom - rect.top);
2339 }
2340 }
2341
2342 // Find a line map (mapping character offsets to text nodes) and a
2343 // measurement cache for the given line number. (A line view might
2344 // contain multiple lines when collapsed ranges are present.)
2345 function mapFromLineView(lineView, line, lineN) {
2346 if (lineView.line == line)
2347 { return {map: lineView.measure.map, cache: lineView.measure.cache} }
2348 for (var i = 0; i < lineView.rest.length; i++)
2349 { if (lineView.rest[i] == line)
2350 { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
2351 for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
2352 { if (lineNo(lineView.rest[i$1]) > lineN)
2353 { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
2354 }
2355
2356 // Render a line into the hidden node display.externalMeasured. Used
2357 // when measurement is needed for a line that's not in the viewport.
2358 function updateExternalMeasurement(cm, line) {
2359 line = visualLine(line);
2360 var lineN = lineNo(line);
2361 var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
2362 view.lineN = lineN;
2363 var built = view.built = buildLineContent(cm, view);
2364 view.text = built.pre;
2365 removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
2366 return view
2367 }
2368
2369 // Get a {top, bottom, left, right} box (in line-local coordinates)
2370 // for a given character.
2371 function measureChar(cm, line, ch, bias) {
2372 return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
2373 }
2374
2375 // Find a line view that corresponds to the given line number.
2376 function findViewForLine(cm, lineN) {
2377 if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
2378 { return cm.display.view[findViewIndex(cm, lineN)] }
2379 var ext = cm.display.externalMeasured;
2380 if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
2381 { return ext }
2382 }
2383
2384 // Measurement can be split in two steps, the set-up work that
2385 // applies to the whole line, and the measurement of the actual
2386 // character. Functions like coordsChar, that need to do a lot of
2387 // measurements in a row, can thus ensure that the set-up work is
2388 // only done once.
2389 function prepareMeasureForLine(cm, line) {
2390 var lineN = lineNo(line);
2391 var view = findViewForLine(cm, lineN);
2392 if (view && !view.text) {
2393 view = null;
2394 } else if (view && view.changes) {
2395 updateLineForChanges(cm, view, lineN, getDimensions(cm));
2396 cm.curOp.forceUpdate = true;
2397 }
2398 if (!view)
2399 { view = updateExternalMeasurement(cm, line); }
2400
2401 var info = mapFromLineView(view, line, lineN);
2402 return {
2403 line: line, view: view, rect: null,
2404 map: info.map, cache: info.cache, before: info.before,
2405 hasHeights: false
2406 }
2407 }
2408
2409 // Given a prepared measurement object, measures the position of an
2410 // actual character (or fetches it from the cache).
2411 function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
2412 if (prepared.before) { ch = -1; }
2413 var key = ch + (bias || ""), found;
2414 if (prepared.cache.hasOwnProperty(key)) {
2415 found = prepared.cache[key];
2416 } else {
2417 if (!prepared.rect)
2418 { prepared.rect = prepared.view.text.getBoundingClientRect(); }
2419 if (!prepared.hasHeights) {
2420 ensureLineHeights(cm, prepared.view, prepared.rect);
2421 prepared.hasHeights = true;
2422 }
2423 found = measureCharInner(cm, prepared, ch, bias);
2424 if (!found.bogus) { prepared.cache[key] = found; }
2425 }
2426 return {left: found.left, right: found.right,
2427 top: varHeight ? found.rtop : found.top,
2428 bottom: varHeight ? found.rbottom : found.bottom}
2429 }
2430
2431 var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
2432
2433 function nodeAndOffsetInLineMap(map$$1, ch, bias) {
2434 var node, start, end, collapse, mStart, mEnd;
2435 // First, search the line map for the text node corresponding to,
2436 // or closest to, the target character.
2437 for (var i = 0; i < map$$1.length; i += 3) {
2438 mStart = map$$1[i];
2439 mEnd = map$$1[i + 1];
2440 if (ch < mStart) {
2441 start = 0; end = 1;
2442 collapse = "left";
2443 } else if (ch < mEnd) {
2444 start = ch - mStart;
2445 end = start + 1;
2446 } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
2447 end = mEnd - mStart;
2448 start = end - 1;
2449 if (ch >= mEnd) { collapse = "right"; }
2450 }
2451 if (start != null) {
2452 node = map$$1[i + 2];
2453 if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
2454 { collapse = bias; }
2455 if (bias == "left" && start == 0)
2456 { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
2457 node = map$$1[(i -= 3) + 2];
2458 collapse = "left";
2459 } }
2460 if (bias == "right" && start == mEnd - mStart)
2461 { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
2462 node = map$$1[(i += 3) + 2];
2463 collapse = "right";
2464 } }
2465 break
2466 }
2467 }
2468 return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
2469 }
2470
2471 function getUsefulRect(rects, bias) {
2472 var rect = nullRect;
2473 if (bias == "left") { for (var i = 0; i < rects.length; i++) {
2474 if ((rect = rects[i]).left != rect.right) { break }
2475 } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
2476 if ((rect = rects[i$1]).left != rect.right) { break }
2477 } }
2478 return rect
2479 }
2480
2481 function measureCharInner(cm, prepared, ch, bias) {
2482 var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
2483 var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
2484
2485 var rect;
2486 if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
2487 for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
2488 while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
2489 while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
2490 if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
2491 { rect = node.parentNode.getBoundingClientRect(); }
2492 else
2493 { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
2494 if (rect.left || rect.right || start == 0) { break }
2495 end = start;
2496 start = start - 1;
2497 collapse = "right";
2498 }
2499 if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
2500 } else { // If it is a widget, simply get the box for the whole widget.
2501 if (start > 0) { collapse = bias = "right"; }
2502 var rects;
2503 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
2504 { rect = rects[bias == "right" ? rects.length - 1 : 0]; }
2505 else
2506 { rect = node.getBoundingClientRect(); }
2507 }
2508 if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
2509 var rSpan = node.parentNode.getClientRects()[0];
2510 if (rSpan)
2511 { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
2512 else
2513 { rect = nullRect; }
2514 }
2515
2516 var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
2517 var mid = (rtop + rbot) / 2;
2518 var heights = prepared.view.measure.heights;
2519 var i = 0;
2520 for (; i < heights.length - 1; i++)
2521 { if (mid < heights[i]) { break } }
2522 var top = i ? heights[i - 1] : 0, bot = heights[i];
2523 var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
2524 right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
2525 top: top, bottom: bot};
2526 if (!rect.left && !rect.right) { result.bogus = true; }
2527 if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
2528
2529 return result
2530 }
2531
2532 // Work around problem with bounding client rects on ranges being
2533 // returned incorrectly when zoomed on IE10 and below.
2534 function maybeUpdateRectForZooming(measure, rect) {
2535 if (!window.screen || screen.logicalXDPI == null ||
2536 screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
2537 { return rect }
2538 var scaleX = screen.logicalXDPI / screen.deviceXDPI;
2539 var scaleY = screen.logicalYDPI / screen.deviceYDPI;
2540 return {left: rect.left * scaleX, right: rect.right * scaleX,
2541 top: rect.top * scaleY, bottom: rect.bottom * scaleY}
2542 }
2543
2544 function clearLineMeasurementCacheFor(lineView) {
2545 if (lineView.measure) {
2546 lineView.measure.cache = {};
2547 lineView.measure.heights = null;
2548 if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
2549 { lineView.measure.caches[i] = {}; } }
2550 }
2551 }
2552
2553 function clearLineMeasurementCache(cm) {
2554 cm.display.externalMeasure = null;
2555 removeChildren(cm.display.lineMeasure);
2556 for (var i = 0; i < cm.display.view.length; i++)
2557 { clearLineMeasurementCacheFor(cm.display.view[i]); }
2558 }
2559
2560 function clearCaches(cm) {
2561 clearLineMeasurementCache(cm);
2562 cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
2563 if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
2564 cm.display.lineNumChars = null;
2565 }
2566
2567 function pageScrollX() {
2568 // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
2569 // which causes page_Offset and bounding client rects to use
2570 // different reference viewports and invalidate our calculations.
2571 if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
2572 return window.pageXOffset || (document.documentElement || document.body).scrollLeft
2573 }
2574 function pageScrollY() {
2575 if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
2576 return window.pageYOffset || (document.documentElement || document.body).scrollTop
2577 }
2578
2579 function widgetTopHeight(lineObj) {
2580 var height = 0;
2581 if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
2582 { height += widgetHeight(lineObj.widgets[i]); } } }
2583 return height
2584 }
2585
2586 // Converts a {top, bottom, left, right} box from line-local
2587 // coordinates into another coordinate system. Context may be one of
2588 // "line", "div" (display.lineDiv), "local"./null (editor), "window",
2589 // or "page".
2590 function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
2591 if (!includeWidgets) {
2592 var height = widgetTopHeight(lineObj);
2593 rect.top += height; rect.bottom += height;
2594 }
2595 if (context == "line") { return rect }
2596 if (!context) { context = "local"; }
2597 var yOff = heightAtLine(lineObj);
2598 if (context == "local") { yOff += paddingTop(cm.display); }
2599 else { yOff -= cm.display.viewOffset; }
2600 if (context == "page" || context == "window") {
2601 var lOff = cm.display.lineSpace.getBoundingClientRect();
2602 yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
2603 var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
2604 rect.left += xOff; rect.right += xOff;
2605 }
2606 rect.top += yOff; rect.bottom += yOff;
2607 return rect
2608 }
2609
2610 // Coverts a box from "div" coords to another coordinate system.
2611 // Context may be "window", "page", "div", or "local"./null.
2612 function fromCoordSystem(cm, coords, context) {
2613 if (context == "div") { return coords }
2614 var left = coords.left, top = coords.top;
2615 // First move into "page" coordinate system
2616 if (context == "page") {
2617 left -= pageScrollX();
2618 top -= pageScrollY();
2619 } else if (context == "local" || !context) {
2620 var localBox = cm.display.sizer.getBoundingClientRect();
2621 left += localBox.left;
2622 top += localBox.top;
2623 }
2624
2625 var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
2626 return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
2627 }
2628
2629 function charCoords(cm, pos, context, lineObj, bias) {
2630 if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
2631 return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
2632 }
2633
2634 // Returns a box for a given cursor position, which may have an
2635 // 'other' property containing the position of the secondary cursor
2636 // on a bidi boundary.
2637 // A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
2638 // and after `char - 1` in writing order of `char - 1`
2639 // A cursor Pos(line, char, "after") is on the same visual line as `char`
2640 // and before `char` in writing order of `char`
2641 // Examples (upper-case letters are RTL, lower-case are LTR):
2642 // Pos(0, 1, ...)
2643 // before after
2644 // ab a|b a|b
2645 // aB a|B aB|
2646 // Ab |Ab A|b
2647 // AB B|A B|A
2648 // Every position after the last character on a line is considered to stick
2649 // to the last character on the line.
2650 function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
2651 lineObj = lineObj || getLine(cm.doc, pos.line);
2652 if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
2653 function get(ch, right) {
2654 var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
2655 if (right) { m.left = m.right; } else { m.right = m.left; }
2656 return intoCoordSystem(cm, lineObj, m, context)
2657 }
2658 var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
2659 if (ch >= lineObj.text.length) {
2660 ch = lineObj.text.length;
2661 sticky = "before";
2662 } else if (ch <= 0) {
2663 ch = 0;
2664 sticky = "after";
2665 }
2666 if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
2667
2668 function getBidi(ch, partPos, invert) {
2669 var part = order[partPos], right = part.level == 1;
2670 return get(invert ? ch - 1 : ch, right != invert)
2671 }
2672 var partPos = getBidiPartAt(order, ch, sticky);
2673 var other = bidiOther;
2674 var val = getBidi(ch, partPos, sticky == "before");
2675 if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
2676 return val
2677 }
2678
2679 // Used to cheaply estimate the coordinates for a position. Used for
2680 // intermediate scroll updates.
2681 function estimateCoords(cm, pos) {
2682 var left = 0;
2683 pos = clipPos(cm.doc, pos);
2684 if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
2685 var lineObj = getLine(cm.doc, pos.line);
2686 var top = heightAtLine(lineObj) + paddingTop(cm.display);
2687 return {left: left, right: left, top: top, bottom: top + lineObj.height}
2688 }
2689
2690 // Positions returned by coordsChar contain some extra information.
2691 // xRel is the relative x position of the input coordinates compared
2692 // to the found position (so xRel > 0 means the coordinates are to
2693 // the right of the character position, for example). When outside
2694 // is true, that means the coordinates lie outside the line's
2695 // vertical range.
2696 function PosWithInfo(line, ch, sticky, outside, xRel) {
2697 var pos = Pos(line, ch, sticky);
2698 pos.xRel = xRel;
2699 if (outside) { pos.outside = outside; }
2700 return pos
2701 }
2702
2703 // Compute the character position closest to the given coordinates.
2704 // Input must be lineSpace-local ("div" coordinate system).
2705 function coordsChar(cm, x, y) {
2706 var doc = cm.doc;
2707 y += cm.display.viewOffset;
2708 if (y < 0) { return PosWithInfo(doc.first, 0, null, -1, -1) }
2709 var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
2710 if (lineN > last)
2711 { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, 1, 1) }
2712 if (x < 0) { x = 0; }
2713
2714 var lineObj = getLine(doc, lineN);
2715 for (;;) {
2716 var found = coordsCharInner(cm, lineObj, lineN, x, y);
2717 var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 || found.outside > 0 ? 1 : 0));
2718 if (!collapsed) { return found }
2719 var rangeEnd = collapsed.find(1);
2720 if (rangeEnd.line == lineN) { return rangeEnd }
2721 lineObj = getLine(doc, lineN = rangeEnd.line);
2722 }
2723 }
2724
2725 function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
2726 y -= widgetTopHeight(lineObj);
2727 var end = lineObj.text.length;
2728 var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);
2729 end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);
2730 return {begin: begin, end: end}
2731 }
2732
2733 function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
2734 if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
2735 var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
2736 return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
2737 }
2738
2739 // Returns true if the given side of a box is after the given
2740 // coordinates, in top-to-bottom, left-to-right order.
2741 function boxIsAfter(box, x, y, left) {
2742 return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
2743 }
2744
2745 function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
2746 // Move y into line-local coordinate space
2747 y -= heightAtLine(lineObj);
2748 var preparedMeasure = prepareMeasureForLine(cm, lineObj);
2749 // When directly calling `measureCharPrepared`, we have to adjust
2750 // for the widgets at this line.
2751 var widgetHeight$$1 = widgetTopHeight(lineObj);
2752 var begin = 0, end = lineObj.text.length, ltr = true;
2753
2754 var order = getOrder(lineObj, cm.doc.direction);
2755 // If the line isn't plain left-to-right text, first figure out
2756 // which bidi section the coordinates fall into.
2757 if (order) {
2758 var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
2759 (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);
2760 ltr = part.level != 1;
2761 // The awkward -1 offsets are needed because findFirst (called
2762 // on these below) will treat its first bound as inclusive,
2763 // second as exclusive, but we want to actually address the
2764 // characters in the part's range
2765 begin = ltr ? part.from : part.to - 1;
2766 end = ltr ? part.to : part.from - 1;
2767 }
2768
2769 // A binary search to find the first character whose bounding box
2770 // starts after the coordinates. If we run across any whose box wrap
2771 // the coordinates, store that.
2772 var chAround = null, boxAround = null;
2773 var ch = findFirst(function (ch) {
2774 var box = measureCharPrepared(cm, preparedMeasure, ch);
2775 box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;
2776 if (!boxIsAfter(box, x, y, false)) { return false }
2777 if (box.top <= y && box.left <= x) {
2778 chAround = ch;
2779 boxAround = box;
2780 }
2781 return true
2782 }, begin, end);
2783
2784 var baseX, sticky, outside = false;
2785 // If a box around the coordinates was found, use that
2786 if (boxAround) {
2787 // Distinguish coordinates nearer to the left or right side of the box
2788 var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;
2789 ch = chAround + (atStart ? 0 : 1);
2790 sticky = atStart ? "after" : "before";
2791 baseX = atLeft ? boxAround.left : boxAround.right;
2792 } else {
2793 // (Adjust for extended bound, if necessary.)
2794 if (!ltr && (ch == end || ch == begin)) { ch++; }
2795 // To determine which side to associate with, get the box to the
2796 // left of the character and compare it's vertical position to the
2797 // coordinates
2798 sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
2799 (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?
2800 "after" : "before";
2801 // Now get accurate coordinates for this place, in order to get a
2802 // base X position
2803 var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure);
2804 baseX = coords.left;
2805 outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0;
2806 }
2807
2808 ch = skipExtendingChars(lineObj.text, ch, 1);
2809 return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)
2810 }
2811
2812 function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {
2813 // Bidi parts are sorted left-to-right, and in a non-line-wrapping
2814 // situation, we can take this ordering to correspond to the visual
2815 // ordering. This finds the first part whose end is after the given
2816 // coordinates.
2817 var index = findFirst(function (i) {
2818 var part = order[i], ltr = part.level != 1;
2819 return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"),
2820 "line", lineObj, preparedMeasure), x, y, true)
2821 }, 0, order.length - 1);
2822 var part = order[index];
2823 // If this isn't the first part, the part's start is also after
2824 // the coordinates, and the coordinates aren't on the same line as
2825 // that start, move one part back.
2826 if (index > 0) {
2827 var ltr = part.level != 1;
2828 var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"),
2829 "line", lineObj, preparedMeasure);
2830 if (boxIsAfter(start, x, y, true) && start.top > y)
2831 { part = order[index - 1]; }
2832 }
2833 return part
2834 }
2835
2836 function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
2837 // In a wrapped line, rtl text on wrapping boundaries can do things
2838 // that don't correspond to the ordering in our `order` array at
2839 // all, so a binary search doesn't work, and we want to return a
2840 // part that only spans one line so that the binary search in
2841 // coordsCharInner is safe. As such, we first find the extent of the
2842 // wrapped line, and then do a flat search in which we discard any
2843 // spans that aren't on the line.
2844 var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
2845 var begin = ref.begin;
2846 var end = ref.end;
2847 if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; }
2848 var part = null, closestDist = null;
2849 for (var i = 0; i < order.length; i++) {
2850 var p = order[i];
2851 if (p.from >= end || p.to <= begin) { continue }
2852 var ltr = p.level != 1;
2853 var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;
2854 // Weigh against spans ending before this, so that they are only
2855 // picked if nothing ends after
2856 var dist = endX < x ? x - endX + 1e9 : endX - x;
2857 if (!part || closestDist > dist) {
2858 part = p;
2859 closestDist = dist;
2860 }
2861 }
2862 if (!part) { part = order[order.length - 1]; }
2863 // Clip the part to the wrapped line.
2864 if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }
2865 if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }
2866 return part
2867 }
2868
2869 var measureText;
2870 // Compute the default text height.
2871 function textHeight(display) {
2872 if (display.cachedTextHeight != null) { return display.cachedTextHeight }
2873 if (measureText == null) {
2874 measureText = elt("pre", null, "CodeMirror-line-like");
2875 // Measure a bunch of lines, for browsers that compute
2876 // fractional heights.
2877 for (var i = 0; i < 49; ++i) {
2878 measureText.appendChild(document.createTextNode("x"));
2879 measureText.appendChild(elt("br"));
2880 }
2881 measureText.appendChild(document.createTextNode("x"));
2882 }
2883 removeChildrenAndAdd(display.measure, measureText);
2884 var height = measureText.offsetHeight / 50;
2885 if (height > 3) { display.cachedTextHeight = height; }
2886 removeChildren(display.measure);
2887 return height || 1
2888 }
2889
2890 // Compute the default character width.
2891 function charWidth(display) {
2892 if (display.cachedCharWidth != null) { return display.cachedCharWidth }
2893 var anchor = elt("span", "xxxxxxxxxx");
2894 var pre = elt("pre", [anchor], "CodeMirror-line-like");
2895 removeChildrenAndAdd(display.measure, pre);
2896 var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
2897 if (width > 2) { display.cachedCharWidth = width; }
2898 return width || 10
2899 }
2900
2901 // Do a bulk-read of the DOM positions and sizes needed to draw the
2902 // view, so that we don't interleave reading and writing to the DOM.
2903 function getDimensions(cm) {
2904 var d = cm.display, left = {}, width = {};
2905 var gutterLeft = d.gutters.clientLeft;
2906 for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
2907 var id = cm.display.gutterSpecs[i].className;
2908 left[id] = n.offsetLeft + n.clientLeft + gutterLeft;
2909 width[id] = n.clientWidth;
2910 }
2911 return {fixedPos: compensateForHScroll(d),
2912 gutterTotalWidth: d.gutters.offsetWidth,
2913 gutterLeft: left,
2914 gutterWidth: width,
2915 wrapperWidth: d.wrapper.clientWidth}
2916 }
2917
2918 // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
2919 // but using getBoundingClientRect to get a sub-pixel-accurate
2920 // result.
2921 function compensateForHScroll(display) {
2922 return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
2923 }
2924
2925 // Returns a function that estimates the height of a line, to use as
2926 // first approximation until the line becomes visible (and is thus
2927 // properly measurable).
2928 function estimateHeight(cm) {
2929 var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
2930 var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
2931 return function (line) {
2932 if (lineIsHidden(cm.doc, line)) { return 0 }
2933
2934 var widgetsHeight = 0;
2935 if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
2936 if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
2937 } }
2938
2939 if (wrapping)
2940 { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
2941 else
2942 { return widgetsHeight + th }
2943 }
2944 }
2945
2946 function estimateLineHeights(cm) {
2947 var doc = cm.doc, est = estimateHeight(cm);
2948 doc.iter(function (line) {
2949 var estHeight = est(line);
2950 if (estHeight != line.height) { updateLineHeight(line, estHeight); }
2951 });
2952 }
2953
2954 // Given a mouse event, find the corresponding position. If liberal
2955 // is false, it checks whether a gutter or scrollbar was clicked,
2956 // and returns null if it was. forRect is used by rectangular
2957 // selections, and tries to estimate a character position even for
2958 // coordinates beyond the right of the text.
2959 function posFromMouse(cm, e, liberal, forRect) {
2960 var display = cm.display;
2961 if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
2962
2963 var x, y, space = display.lineSpace.getBoundingClientRect();
2964 // Fails unpredictably on IE[67] when mouse is dragged around quickly.
2965 try { x = e.clientX - space.left; y = e.clientY - space.top; }
2966 catch (e) { return null }
2967 var coords = coordsChar(cm, x, y), line;
2968 if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
2969 var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
2970 coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
2971 }
2972 return coords
2973 }
2974
2975 // Find the view element corresponding to a given line. Return null
2976 // when the line isn't visible.
2977 function findViewIndex(cm, n) {
2978 if (n >= cm.display.viewTo) { return null }
2979 n -= cm.display.viewFrom;
2980 if (n < 0) { return null }
2981 var view = cm.display.view;
2982 for (var i = 0; i < view.length; i++) {
2983 n -= view[i].size;
2984 if (n < 0) { return i }
2985 }
2986 }
2987
2988 // Updates the display.view data structure for a given change to the
2989 // document. From and to are in pre-change coordinates. Lendiff is
2990 // the amount of lines added or subtracted by the change. This is
2991 // used for changes that span multiple lines, or change the way
2992 // lines are divided into visual lines. regLineChange (below)
2993 // registers single-line changes.
2994 function regChange(cm, from, to, lendiff) {
2995 if (from == null) { from = cm.doc.first; }
2996 if (to == null) { to = cm.doc.first + cm.doc.size; }
2997 if (!lendiff) { lendiff = 0; }
2998
2999 var display = cm.display;
3000 if (lendiff && to < display.viewTo &&
3001 (display.updateLineNumbers == null || display.updateLineNumbers > from))
3002 { display.updateLineNumbers = from; }
3003
3004 cm.curOp.viewChanged = true;
3005
3006 if (from >= display.viewTo) { // Change after
3007 if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
3008 { resetView(cm); }
3009 } else if (to <= display.viewFrom) { // Change before
3010 if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
3011 resetView(cm);
3012 } else {
3013 display.viewFrom += lendiff;
3014 display.viewTo += lendiff;
3015 }
3016 } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
3017 resetView(cm);
3018 } else if (from <= display.viewFrom) { // Top overlap
3019 var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
3020 if (cut) {
3021 display.view = display.view.slice(cut.index);
3022 display.viewFrom = cut.lineN;
3023 display.viewTo += lendiff;
3024 } else {
3025 resetView(cm);
3026 }
3027 } else if (to >= display.viewTo) { // Bottom overlap
3028 var cut$1 = viewCuttingPoint(cm, from, from, -1);
3029 if (cut$1) {
3030 display.view = display.view.slice(0, cut$1.index);
3031 display.viewTo = cut$1.lineN;
3032 } else {
3033 resetView(cm);
3034 }
3035 } else { // Gap in the middle
3036 var cutTop = viewCuttingPoint(cm, from, from, -1);
3037 var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
3038 if (cutTop && cutBot) {
3039 display.view = display.view.slice(0, cutTop.index)
3040 .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
3041 .concat(display.view.slice(cutBot.index));
3042 display.viewTo += lendiff;
3043 } else {
3044 resetView(cm);
3045 }
3046 }
3047
3048 var ext = display.externalMeasured;
3049 if (ext) {
3050 if (to < ext.lineN)
3051 { ext.lineN += lendiff; }
3052 else if (from < ext.lineN + ext.size)
3053 { display.externalMeasured = null; }
3054 }
3055 }
3056
3057 // Register a change to a single line. Type must be one of "text",
3058 // "gutter", "class", "widget"
3059 function regLineChange(cm, line, type) {
3060 cm.curOp.viewChanged = true;
3061 var display = cm.display, ext = cm.display.externalMeasured;
3062 if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
3063 { display.externalMeasured = null; }
3064
3065 if (line < display.viewFrom || line >= display.viewTo) { return }
3066 var lineView = display.view[findViewIndex(cm, line)];
3067 if (lineView.node == null) { return }
3068 var arr = lineView.changes || (lineView.changes = []);
3069 if (indexOf(arr, type) == -1) { arr.push(type); }
3070 }
3071
3072 // Clear the view.
3073 function resetView(cm) {
3074 cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
3075 cm.display.view = [];
3076 cm.display.viewOffset = 0;
3077 }
3078
3079 function viewCuttingPoint(cm, oldN, newN, dir) {
3080 var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
3081 if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
3082 { return {index: index, lineN: newN} }
3083 var n = cm.display.viewFrom;
3084 for (var i = 0; i < index; i++)
3085 { n += view[i].size; }
3086 if (n != oldN) {
3087 if (dir > 0) {
3088 if (index == view.length - 1) { return null }
3089 diff = (n + view[index].size) - oldN;
3090 index++;
3091 } else {
3092 diff = n - oldN;
3093 }
3094 oldN += diff; newN += diff;
3095 }
3096 while (visualLineNo(cm.doc, newN) != newN) {
3097 if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
3098 newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
3099 index += dir;
3100 }
3101 return {index: index, lineN: newN}
3102 }
3103
3104 // Force the view to cover a given range, adding empty view element
3105 // or clipping off existing ones as needed.
3106 function adjustView(cm, from, to) {
3107 var display = cm.display, view = display.view;
3108 if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
3109 display.view = buildViewArray(cm, from, to);
3110 display.viewFrom = from;
3111 } else {
3112 if (display.viewFrom > from)
3113 { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
3114 else if (display.viewFrom < from)
3115 { display.view = display.view.slice(findViewIndex(cm, from)); }
3116 display.viewFrom = from;
3117 if (display.viewTo < to)
3118 { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
3119 else if (display.viewTo > to)
3120 { display.view = display.view.slice(0, findViewIndex(cm, to)); }
3121 }
3122 display.viewTo = to;
3123 }
3124
3125 // Count the number of lines in the view whose DOM representation is
3126 // out of date (or nonexistent).
3127 function countDirtyView(cm) {
3128 var view = cm.display.view, dirty = 0;
3129 for (var i = 0; i < view.length; i++) {
3130 var lineView = view[i];
3131 if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
3132 }
3133 return dirty
3134 }
3135
3136 function updateSelection(cm) {
3137 cm.display.input.showSelection(cm.display.input.prepareSelection());
3138 }
3139
3140 function prepareSelection(cm, primary) {
3141 if ( primary === void 0 ) primary = true;
3142
3143 var doc = cm.doc, result = {};
3144 var curFragment = result.cursors = document.createDocumentFragment();
3145 var selFragment = result.selection = document.createDocumentFragment();
3146
3147 for (var i = 0; i < doc.sel.ranges.length; i++) {
3148 if (!primary && i == doc.sel.primIndex) { continue }
3149 var range$$1 = doc.sel.ranges[i];
3150 if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }
3151 var collapsed = range$$1.empty();
3152 if (collapsed || cm.options.showCursorWhenSelecting)
3153 { drawSelectionCursor(cm, range$$1.head, curFragment); }
3154 if (!collapsed)
3155 { drawSelectionRange(cm, range$$1, selFragment); }
3156 }
3157 return result
3158 }
3159
3160 // Draws a cursor for the given range
3161 function drawSelectionCursor(cm, head, output) {
3162 var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
3163
3164 var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
3165 cursor.style.left = pos.left + "px";
3166 cursor.style.top = pos.top + "px";
3167 cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
3168
3169 if (pos.other) {
3170 // Secondary cursor, shown when on a 'jump' in bi-directional text
3171 var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
3172 otherCursor.style.display = "";
3173 otherCursor.style.left = pos.other.left + "px";
3174 otherCursor.style.top = pos.other.top + "px";
3175 otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
3176 }
3177 }
3178
3179 function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
3180
3181 // Draws the given range as a highlighted selection
3182 function drawSelectionRange(cm, range$$1, output) {
3183 var display = cm.display, doc = cm.doc;
3184 var fragment = document.createDocumentFragment();
3185 var padding = paddingH(cm.display), leftSide = padding.left;
3186 var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
3187 var docLTR = doc.direction == "ltr";
3188
3189 function add(left, top, width, bottom) {
3190 if (top < 0) { top = 0; }
3191 top = Math.round(top);
3192 bottom = Math.round(bottom);
3193 fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px")));
3194 }
3195
3196 function drawForLine(line, fromArg, toArg) {
3197 var lineObj = getLine(doc, line);
3198 var lineLen = lineObj.text.length;
3199 var start, end;
3200 function coords(ch, bias) {
3201 return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
3202 }
3203
3204 function wrapX(pos, dir, side) {
3205 var extent = wrappedLineExtentChar(cm, lineObj, null, pos);
3206 var prop = (dir == "ltr") == (side == "after") ? "left" : "right";
3207 var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);
3208 return coords(ch, prop)[prop]
3209 }
3210
3211 var order = getOrder(lineObj, doc.direction);
3212 iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
3213 var ltr = dir == "ltr";
3214 var fromPos = coords(from, ltr ? "left" : "right");
3215 var toPos = coords(to - 1, ltr ? "right" : "left");
3216
3217 var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;
3218 var first = i == 0, last = !order || i == order.length - 1;
3219 if (toPos.top - fromPos.top <= 3) { // Single line
3220 var openLeft = (docLTR ? openStart : openEnd) && first;
3221 var openRight = (docLTR ? openEnd : openStart) && last;
3222 var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;
3223 var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;
3224 add(left, fromPos.top, right - left, fromPos.bottom);
3225 } else { // Multiple lines
3226 var topLeft, topRight, botLeft, botRight;
3227 if (ltr) {
3228 topLeft = docLTR && openStart && first ? leftSide : fromPos.left;
3229 topRight = docLTR ? rightSide : wrapX(from, dir, "before");
3230 botLeft = docLTR ? leftSide : wrapX(to, dir, "after");
3231 botRight = docLTR && openEnd && last ? rightSide : toPos.right;
3232 } else {
3233 topLeft = !docLTR ? leftSide : wrapX(from, dir, "before");
3234 topRight = !docLTR && openStart && first ? rightSide : fromPos.right;
3235 botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;
3236 botRight = !docLTR ? rightSide : wrapX(to, dir, "after");
3237 }
3238 add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);
3239 if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }
3240 add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);
3241 }
3242
3243 if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }
3244 if (cmpCoords(toPos, start) < 0) { start = toPos; }
3245 if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }
3246 if (cmpCoords(toPos, end) < 0) { end = toPos; }
3247 });
3248 return {start: start, end: end}
3249 }
3250
3251 var sFrom = range$$1.from(), sTo = range$$1.to();
3252 if (sFrom.line == sTo.line) {
3253 drawForLine(sFrom.line, sFrom.ch, sTo.ch);
3254 } else {
3255 var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
3256 var singleVLine = visualLine(fromLine) == visualLine(toLine);
3257 var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
3258 var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
3259 if (singleVLine) {
3260 if (leftEnd.top < rightStart.top - 2) {
3261 add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
3262 add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
3263 } else {
3264 add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
3265 }
3266 }
3267 if (leftEnd.bottom < rightStart.top)
3268 { add(leftSide, leftEnd.bottom, null, rightStart.top); }
3269 }
3270
3271 output.appendChild(fragment);
3272 }
3273
3274 // Cursor-blinking
3275 function restartBlink(cm) {
3276 if (!cm.state.focused) { return }
3277 var display = cm.display;
3278 clearInterval(display.blinker);
3279 var on = true;
3280 display.cursorDiv.style.visibility = "";
3281 if (cm.options.cursorBlinkRate > 0)
3282 { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
3283 cm.options.cursorBlinkRate); }
3284 else if (cm.options.cursorBlinkRate < 0)
3285 { display.cursorDiv.style.visibility = "hidden"; }
3286 }
3287
3288 function ensureFocus(cm) {
3289 if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
3290 }
3291
3292 function delayBlurEvent(cm) {
3293 cm.state.delayingBlurEvent = true;
3294 setTimeout(function () { if (cm.state.delayingBlurEvent) {
3295 cm.state.delayingBlurEvent = false;
3296 onBlur(cm);
3297 } }, 100);
3298 }
3299
3300 function onFocus(cm, e) {
3301 if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
3302
3303 if (cm.options.readOnly == "nocursor") { return }
3304 if (!cm.state.focused) {
3305 signal(cm, "focus", cm, e);
3306 cm.state.focused = true;
3307 addClass(cm.display.wrapper, "CodeMirror-focused");
3308 // This test prevents this from firing when a context
3309 // menu is closed (since the input reset would kill the
3310 // select-all detection hack)
3311 if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
3312 cm.display.input.reset();
3313 if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
3314 }
3315 cm.display.input.receivedFocus();
3316 }
3317 restartBlink(cm);
3318 }
3319 function onBlur(cm, e) {
3320 if (cm.state.delayingBlurEvent) { return }
3321
3322 if (cm.state.focused) {
3323 signal(cm, "blur", cm, e);
3324 cm.state.focused = false;
3325 rmClass(cm.display.wrapper, "CodeMirror-focused");
3326 }
3327 clearInterval(cm.display.blinker);
3328 setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
3329 }
3330
3331 // Read the actual heights of the rendered lines, and update their
3332 // stored heights to match.
3333 function updateHeightsInViewport(cm) {
3334 var display = cm.display;
3335 var prevBottom = display.lineDiv.offsetTop;
3336 for (var i = 0; i < display.view.length; i++) {
3337 var cur = display.view[i], wrapping = cm.options.lineWrapping;
3338 var height = (void 0), width = 0;
3339 if (cur.hidden) { continue }
3340 if (ie && ie_version < 8) {
3341 var bot = cur.node.offsetTop + cur.node.offsetHeight;
3342 height = bot - prevBottom;
3343 prevBottom = bot;
3344 } else {
3345 var box = cur.node.getBoundingClientRect();
3346 height = box.bottom - box.top;
3347 // Check that lines don't extend past the right of the current
3348 // editor width
3349 if (!wrapping && cur.text.firstChild)
3350 { width = cur.text.firstChild.getBoundingClientRect().right - box.left - 1; }
3351 }
3352 var diff = cur.line.height - height;
3353 if (diff > .005 || diff < -.005) {
3354 updateLineHeight(cur.line, height);
3355 updateWidgetHeight(cur.line);
3356 if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
3357 { updateWidgetHeight(cur.rest[j]); } }
3358 }
3359 if (width > cm.display.sizerWidth) {
3360 var chWidth = Math.ceil(width / charWidth(cm.display));
3361 if (chWidth > cm.display.maxLineLength) {
3362 cm.display.maxLineLength = chWidth;
3363 cm.display.maxLine = cur.line;
3364 cm.display.maxLineChanged = true;
3365 }
3366 }
3367 }
3368 }
3369
3370 // Read and store the height of line widgets associated with the
3371 // given line.
3372 function updateWidgetHeight(line) {
3373 if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {
3374 var w = line.widgets[i], parent = w.node.parentNode;
3375 if (parent) { w.height = parent.offsetHeight; }
3376 } }
3377 }
3378
3379 // Compute the lines that are visible in a given viewport (defaults
3380 // the the current scroll position). viewport may contain top,
3381 // height, and ensure (see op.scrollToPos) properties.
3382 function visibleLines(display, doc, viewport) {
3383 var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
3384 top = Math.floor(top - paddingTop(display));
3385 var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
3386
3387 var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
3388 // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
3389 // forces those lines into the viewport (if possible).
3390 if (viewport && viewport.ensure) {
3391 var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
3392 if (ensureFrom < from) {
3393 from = ensureFrom;
3394 to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
3395 } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
3396 from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
3397 to = ensureTo;
3398 }
3399 }
3400 return {from: from, to: Math.max(to, from + 1)}
3401 }
3402
3403 // SCROLLING THINGS INTO VIEW
3404
3405 // If an editor sits on the top or bottom of the window, partially
3406 // scrolled out of view, this ensures that the cursor is visible.
3407 function maybeScrollWindow(cm, rect) {
3408 if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
3409
3410 var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
3411 if (rect.top + box.top < 0) { doScroll = true; }
3412 else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
3413 if (doScroll != null && !phantom) {
3414 var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;"));
3415 cm.display.lineSpace.appendChild(scrollNode);
3416 scrollNode.scrollIntoView(doScroll);
3417 cm.display.lineSpace.removeChild(scrollNode);
3418 }
3419 }
3420
3421 // Scroll a given position into view (immediately), verifying that
3422 // it actually became visible (as line heights are accurately
3423 // measured, the position of something may 'drift' during drawing).
3424 function scrollPosIntoView(cm, pos, end, margin) {
3425 if (margin == null) { margin = 0; }
3426 var rect;
3427 if (!cm.options.lineWrapping && pos == end) {
3428 // Set pos and end to the cursor positions around the character pos sticks to
3429 // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
3430 // If pos == Pos(_, 0, "before"), pos and end are unchanged
3431 pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
3432 end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
3433 }
3434 for (var limit = 0; limit < 5; limit++) {
3435 var changed = false;
3436 var coords = cursorCoords(cm, pos);
3437 var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
3438 rect = {left: Math.min(coords.left, endCoords.left),
3439 top: Math.min(coords.top, endCoords.top) - margin,
3440 right: Math.max(coords.left, endCoords.left),
3441 bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
3442 var scrollPos = calculateScrollPos(cm, rect);
3443 var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
3444 if (scrollPos.scrollTop != null) {
3445 updateScrollTop(cm, scrollPos.scrollTop);
3446 if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
3447 }
3448 if (scrollPos.scrollLeft != null) {
3449 setScrollLeft(cm, scrollPos.scrollLeft);
3450 if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
3451 }
3452 if (!changed) { break }
3453 }
3454 return rect
3455 }
3456
3457 // Scroll a given set of coordinates into view (immediately).
3458 function scrollIntoView(cm, rect) {
3459 var scrollPos = calculateScrollPos(cm, rect);
3460 if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
3461 if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
3462 }
3463
3464 // Calculate a new scroll position needed to scroll the given
3465 // rectangle into view. Returns an object with scrollTop and
3466 // scrollLeft properties. When these are undefined, the
3467 // vertical/horizontal position does not need to be adjusted.
3468 function calculateScrollPos(cm, rect) {
3469 var display = cm.display, snapMargin = textHeight(cm.display);
3470 if (rect.top < 0) { rect.top = 0; }
3471 var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
3472 var screen = displayHeight(cm), result = {};
3473 if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
3474 var docBottom = cm.doc.height + paddingVert(display);
3475 var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
3476 if (rect.top < screentop) {
3477 result.scrollTop = atTop ? 0 : rect.top;
3478 } else if (rect.bottom > screentop + screen) {
3479 var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
3480 if (newTop != screentop) { result.scrollTop = newTop; }
3481 }
3482
3483 var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
3484 var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
3485 var tooWide = rect.right - rect.left > screenw;
3486 if (tooWide) { rect.right = rect.left + screenw; }
3487 if (rect.left < 10)
3488 { result.scrollLeft = 0; }
3489 else if (rect.left < screenleft)
3490 { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
3491 else if (rect.right > screenw + screenleft - 3)
3492 { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
3493 return result
3494 }
3495
3496 // Store a relative adjustment to the scroll position in the current
3497 // operation (to be applied when the operation finishes).
3498 function addToScrollTop(cm, top) {
3499 if (top == null) { return }
3500 resolveScrollToPos(cm);
3501 cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
3502 }
3503
3504 // Make sure that at the end of the operation the current cursor is
3505 // shown.
3506 function ensureCursorVisible(cm) {
3507 resolveScrollToPos(cm);
3508 var cur = cm.getCursor();
3509 cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
3510 }
3511
3512 function scrollToCoords(cm, x, y) {
3513 if (x != null || y != null) { resolveScrollToPos(cm); }
3514 if (x != null) { cm.curOp.scrollLeft = x; }
3515 if (y != null) { cm.curOp.scrollTop = y; }
3516 }
3517
3518 function scrollToRange(cm, range$$1) {
3519 resolveScrollToPos(cm);
3520 cm.curOp.scrollToPos = range$$1;
3521 }
3522
3523 // When an operation has its scrollToPos property set, and another
3524 // scroll action is applied before the end of the operation, this
3525 // 'simulates' scrolling that position into view in a cheap way, so
3526 // that the effect of intermediate scroll commands is not ignored.
3527 function resolveScrollToPos(cm) {
3528 var range$$1 = cm.curOp.scrollToPos;
3529 if (range$$1) {
3530 cm.curOp.scrollToPos = null;
3531 var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
3532 scrollToCoordsRange(cm, from, to, range$$1.margin);
3533 }
3534 }
3535
3536 function scrollToCoordsRange(cm, from, to, margin) {
3537 var sPos = calculateScrollPos(cm, {
3538 left: Math.min(from.left, to.left),
3539 top: Math.min(from.top, to.top) - margin,
3540 right: Math.max(from.right, to.right),
3541 bottom: Math.max(from.bottom, to.bottom) + margin
3542 });
3543 scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
3544 }
3545
3546 // Sync the scrollable area and scrollbars, ensure the viewport
3547 // covers the visible area.
3548 function updateScrollTop(cm, val) {
3549 if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
3550 if (!gecko) { updateDisplaySimple(cm, {top: val}); }
3551 setScrollTop(cm, val, true);
3552 if (gecko) { updateDisplaySimple(cm); }
3553 startWorker(cm, 100);
3554 }
3555
3556 function setScrollTop(cm, val, forceScroll) {
3557 val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
3558 if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
3559 cm.doc.scrollTop = val;
3560 cm.display.scrollbars.setScrollTop(val);
3561 if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
3562 }
3563
3564 // Sync scroller and scrollbar, ensure the gutter elements are
3565 // aligned.
3566 function setScrollLeft(cm, val, isScroller, forceScroll) {
3567 val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
3568 if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
3569 cm.doc.scrollLeft = val;
3570 alignHorizontally(cm);
3571 if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
3572 cm.display.scrollbars.setScrollLeft(val);
3573 }
3574
3575 // SCROLLBARS
3576
3577 // Prepare DOM reads needed to update the scrollbars. Done in one
3578 // shot to minimize update/measure roundtrips.
3579 function measureForScrollbars(cm) {
3580 var d = cm.display, gutterW = d.gutters.offsetWidth;
3581 var docH = Math.round(cm.doc.height + paddingVert(cm.display));
3582 return {
3583 clientHeight: d.scroller.clientHeight,
3584 viewHeight: d.wrapper.clientHeight,
3585 scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
3586 viewWidth: d.wrapper.clientWidth,
3587 barLeft: cm.options.fixedGutter ? gutterW : 0,
3588 docHeight: docH,
3589 scrollHeight: docH + scrollGap(cm) + d.barHeight,
3590 nativeBarWidth: d.nativeBarWidth,
3591 gutterWidth: gutterW
3592 }
3593 }
3594
3595 var NativeScrollbars = function(place, scroll, cm) {
3596 this.cm = cm;
3597 var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
3598 var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
3599 vert.tabIndex = horiz.tabIndex = -1;
3600 place(vert); place(horiz);
3601
3602 on(vert, "scroll", function () {
3603 if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
3604 });
3605 on(horiz, "scroll", function () {
3606 if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
3607 });
3608
3609 this.checkedZeroWidth = false;
3610 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
3611 if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
3612 };
3613
3614 NativeScrollbars.prototype.update = function (measure) {
3615 var needsH = measure.scrollWidth > measure.clientWidth + 1;
3616 var needsV = measure.scrollHeight > measure.clientHeight + 1;
3617 var sWidth = measure.nativeBarWidth;
3618
3619 if (needsV) {
3620 this.vert.style.display = "block";
3621 this.vert.style.bottom = needsH ? sWidth + "px" : "0";
3622 var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
3623 // A bug in IE8 can cause this value to be negative, so guard it.
3624 this.vert.firstChild.style.height =
3625 Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
3626 } else {
3627 this.vert.style.display = "";
3628 this.vert.firstChild.style.height = "0";
3629 }
3630
3631 if (needsH) {
3632 this.horiz.style.display = "block";
3633 this.horiz.style.right = needsV ? sWidth + "px" : "0";
3634 this.horiz.style.left = measure.barLeft + "px";
3635 var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
3636 this.horiz.firstChild.style.width =
3637 Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
3638 } else {
3639 this.horiz.style.display = "";
3640 this.horiz.firstChild.style.width = "0";
3641 }
3642
3643 if (!this.checkedZeroWidth && measure.clientHeight > 0) {
3644 if (sWidth == 0) { this.zeroWidthHack(); }
3645 this.checkedZeroWidth = true;
3646 }
3647
3648 return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
3649 };
3650
3651 NativeScrollbars.prototype.setScrollLeft = function (pos) {
3652 if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
3653 if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
3654 };
3655
3656 NativeScrollbars.prototype.setScrollTop = function (pos) {
3657 if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
3658 if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
3659 };
3660
3661 NativeScrollbars.prototype.zeroWidthHack = function () {
3662 var w = mac && !mac_geMountainLion ? "12px" : "18px";
3663 this.horiz.style.height = this.vert.style.width = w;
3664 this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
3665 this.disableHoriz = new Delayed;
3666 this.disableVert = new Delayed;
3667 };
3668
3669 NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
3670 bar.style.pointerEvents = "auto";
3671 function maybeDisable() {
3672 // To find out whether the scrollbar is still visible, we
3673 // check whether the element under the pixel in the bottom
3674 // right corner of the scrollbar box is the scrollbar box
3675 // itself (when the bar is still visible) or its filler child
3676 // (when the bar is hidden). If it is still visible, we keep
3677 // it enabled, if it's hidden, we disable pointer events.
3678 var box = bar.getBoundingClientRect();
3679 var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
3680 : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
3681 if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
3682 else { delay.set(1000, maybeDisable); }
3683 }
3684 delay.set(1000, maybeDisable);
3685 };
3686
3687 NativeScrollbars.prototype.clear = function () {
3688 var parent = this.horiz.parentNode;
3689 parent.removeChild(this.horiz);
3690 parent.removeChild(this.vert);
3691 };
3692
3693 var NullScrollbars = function () {};
3694
3695 NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
3696 NullScrollbars.prototype.setScrollLeft = function () {};
3697 NullScrollbars.prototype.setScrollTop = function () {};
3698 NullScrollbars.prototype.clear = function () {};
3699
3700 function updateScrollbars(cm, measure) {
3701 if (!measure) { measure = measureForScrollbars(cm); }
3702 var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
3703 updateScrollbarsInner(cm, measure);
3704 for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
3705 if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
3706 { updateHeightsInViewport(cm); }
3707 updateScrollbarsInner(cm, measureForScrollbars(cm));
3708 startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
3709 }
3710 }
3711
3712 // Re-synchronize the fake scrollbars with the actual size of the
3713 // content.
3714 function updateScrollbarsInner(cm, measure) {
3715 var d = cm.display;
3716 var sizes = d.scrollbars.update(measure);
3717
3718 d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
3719 d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
3720 d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
3721
3722 if (sizes.right && sizes.bottom) {
3723 d.scrollbarFiller.style.display = "block";
3724 d.scrollbarFiller.style.height = sizes.bottom + "px";
3725 d.scrollbarFiller.style.width = sizes.right + "px";
3726 } else { d.scrollbarFiller.style.display = ""; }
3727 if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
3728 d.gutterFiller.style.display = "block";
3729 d.gutterFiller.style.height = sizes.bottom + "px";
3730 d.gutterFiller.style.width = measure.gutterWidth + "px";
3731 } else { d.gutterFiller.style.display = ""; }
3732 }
3733
3734 var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
3735
3736 function initScrollbars(cm) {
3737 if (cm.display.scrollbars) {
3738 cm.display.scrollbars.clear();
3739 if (cm.display.scrollbars.addClass)
3740 { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
3741 }
3742
3743 cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
3744 cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
3745 // Prevent clicks in the scrollbars from killing focus
3746 on(node, "mousedown", function () {
3747 if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
3748 });
3749 node.setAttribute("cm-not-content", "true");
3750 }, function (pos, axis) {
3751 if (axis == "horizontal") { setScrollLeft(cm, pos); }
3752 else { updateScrollTop(cm, pos); }
3753 }, cm);
3754 if (cm.display.scrollbars.addClass)
3755 { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
3756 }
3757
3758 // Operations are used to wrap a series of changes to the editor
3759 // state in such a way that each change won't have to update the
3760 // cursor and display (which would be awkward, slow, and
3761 // error-prone). Instead, display updates are batched and then all
3762 // combined and executed at once.
3763
3764 var nextOpId = 0;
3765 // Start a new operation.
3766 function startOperation(cm) {
3767 cm.curOp = {
3768 cm: cm,
3769 viewChanged: false, // Flag that indicates that lines might need to be redrawn
3770 startHeight: cm.doc.height, // Used to detect need to update scrollbar
3771 forceUpdate: false, // Used to force a redraw
3772 updateInput: 0, // Whether to reset the input textarea
3773 typing: false, // Whether this reset should be careful to leave existing text (for compositing)
3774 changeObjs: null, // Accumulated changes, for firing change events
3775 cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
3776 cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
3777 selectionChanged: false, // Whether the selection needs to be redrawn
3778 updateMaxLine: false, // Set when the widest line needs to be determined anew
3779 scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
3780 scrollToPos: null, // Used to scroll to a specific position
3781 focus: false,
3782 id: ++nextOpId // Unique ID
3783 };
3784 pushOperation(cm.curOp);
3785 }
3786
3787 // Finish an operation, updating the display and signalling delayed events
3788 function endOperation(cm) {
3789 var op = cm.curOp;
3790 if (op) { finishOperation(op, function (group) {
3791 for (var i = 0; i < group.ops.length; i++)
3792 { group.ops[i].cm.curOp = null; }
3793 endOperations(group);
3794 }); }
3795 }
3796
3797 // The DOM updates done when an operation finishes are batched so
3798 // that the minimum number of relayouts are required.
3799 function endOperations(group) {
3800 var ops = group.ops;
3801 for (var i = 0; i < ops.length; i++) // Read DOM
3802 { endOperation_R1(ops[i]); }
3803 for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
3804 { endOperation_W1(ops[i$1]); }
3805 for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
3806 { endOperation_R2(ops[i$2]); }
3807 for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
3808 { endOperation_W2(ops[i$3]); }
3809 for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
3810 { endOperation_finish(ops[i$4]); }
3811 }
3812
3813 function endOperation_R1(op) {
3814 var cm = op.cm, display = cm.display;
3815 maybeClipScrollbars(cm);
3816 if (op.updateMaxLine) { findMaxLine(cm); }
3817
3818 op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
3819 op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
3820 op.scrollToPos.to.line >= display.viewTo) ||
3821 display.maxLineChanged && cm.options.lineWrapping;
3822 op.update = op.mustUpdate &&
3823 new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
3824 }
3825
3826 function endOperation_W1(op) {
3827 op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
3828 }
3829
3830 function endOperation_R2(op) {
3831 var cm = op.cm, display = cm.display;
3832 if (op.updatedDisplay) { updateHeightsInViewport(cm); }
3833
3834 op.barMeasure = measureForScrollbars(cm);
3835
3836 // If the max line changed since it was last measured, measure it,
3837 // and ensure the document's width matches it.
3838 // updateDisplay_W2 will use these properties to do the actual resizing
3839 if (display.maxLineChanged && !cm.options.lineWrapping) {
3840 op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
3841 cm.display.sizerWidth = op.adjustWidthTo;
3842 op.barMeasure.scrollWidth =
3843 Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
3844 op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
3845 }
3846
3847 if (op.updatedDisplay || op.selectionChanged)
3848 { op.preparedSelection = display.input.prepareSelection(); }
3849 }
3850
3851 function endOperation_W2(op) {
3852 var cm = op.cm;
3853
3854 if (op.adjustWidthTo != null) {
3855 cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
3856 if (op.maxScrollLeft < cm.doc.scrollLeft)
3857 { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
3858 cm.display.maxLineChanged = false;
3859 }
3860
3861 var takeFocus = op.focus && op.focus == activeElt();
3862 if (op.preparedSelection)
3863 { cm.display.input.showSelection(op.preparedSelection, takeFocus); }
3864 if (op.updatedDisplay || op.startHeight != cm.doc.height)
3865 { updateScrollbars(cm, op.barMeasure); }
3866 if (op.updatedDisplay)
3867 { setDocumentHeight(cm, op.barMeasure); }
3868
3869 if (op.selectionChanged) { restartBlink(cm); }
3870
3871 if (cm.state.focused && op.updateInput)
3872 { cm.display.input.reset(op.typing); }
3873 if (takeFocus) { ensureFocus(op.cm); }
3874 }
3875
3876 function endOperation_finish(op) {
3877 var cm = op.cm, display = cm.display, doc = cm.doc;
3878
3879 if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
3880
3881 // Abort mouse wheel delta measurement, when scrolling explicitly
3882 if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
3883 { display.wheelStartX = display.wheelStartY = null; }
3884
3885 // Propagate the scroll position to the actual DOM scroller
3886 if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
3887
3888 if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
3889 // If we need to scroll a specific position into view, do so.
3890 if (op.scrollToPos) {
3891 var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
3892 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
3893 maybeScrollWindow(cm, rect);
3894 }
3895
3896 // Fire events for markers that are hidden/unidden by editing or
3897 // undoing
3898 var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
3899 if (hidden) { for (var i = 0; i < hidden.length; ++i)
3900 { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
3901 if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
3902 { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
3903
3904 if (display.wrapper.offsetHeight)
3905 { doc.scrollTop = cm.display.scroller.scrollTop; }
3906
3907 // Fire change events, and delayed event handlers
3908 if (op.changeObjs)
3909 { signal(cm, "changes", cm, op.changeObjs); }
3910 if (op.update)
3911 { op.update.finish(); }
3912 }
3913
3914 // Run the given function in an operation
3915 function runInOp(cm, f) {
3916 if (cm.curOp) { return f() }
3917 startOperation(cm);
3918 try { return f() }
3919 finally { endOperation(cm); }
3920 }
3921 // Wraps a function in an operation. Returns the wrapped function.
3922 function operation(cm, f) {
3923 return function() {
3924 if (cm.curOp) { return f.apply(cm, arguments) }
3925 startOperation(cm);
3926 try { return f.apply(cm, arguments) }
3927 finally { endOperation(cm); }
3928 }
3929 }
3930 // Used to add methods to editor and doc instances, wrapping them in
3931 // operations.
3932 function methodOp(f) {
3933 return function() {
3934 if (this.curOp) { return f.apply(this, arguments) }
108 startOperation(this);
3935 startOperation(this);
109 this.curOp.forceUpdate = true;
3936 try { return f.apply(this, arguments) }
110 attachDoc(this, doc);
3937 finally { endOperation(this); }
111
3938 }
112 if ((options.autofocus && !mobile) || cm.hasFocus())
3939 }
113 setTimeout(bind(onFocus, this), 20);
3940 function docMethodOp(f) {
3941 return function() {
3942 var cm = this.cm;
3943 if (!cm || cm.curOp) { return f.apply(this, arguments) }
3944 startOperation(cm);
3945 try { return f.apply(this, arguments) }
3946 finally { endOperation(cm); }
3947 }
3948 }
3949
3950 // HIGHLIGHT WORKER
3951
3952 function startWorker(cm, time) {
3953 if (cm.doc.highlightFrontier < cm.display.viewTo)
3954 { cm.state.highlight.set(time, bind(highlightWorker, cm)); }
3955 }
3956
3957 function highlightWorker(cm) {
3958 var doc = cm.doc;
3959 if (doc.highlightFrontier >= cm.display.viewTo) { return }
3960 var end = +new Date + cm.options.workTime;
3961 var context = getContextBefore(cm, doc.highlightFrontier);
3962 var changedLines = [];
3963
3964 doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
3965 if (context.line >= cm.display.viewFrom) { // Visible
3966 var oldStyles = line.styles;
3967 var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
3968 var highlighted = highlightLine(cm, line, context, true);
3969 if (resetState) { context.state = resetState; }
3970 line.styles = highlighted.styles;
3971 var oldCls = line.styleClasses, newCls = highlighted.classes;
3972 if (newCls) { line.styleClasses = newCls; }
3973 else if (oldCls) { line.styleClasses = null; }
3974 var ischange = !oldStyles || oldStyles.length != line.styles.length ||
3975 oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
3976 for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
3977 if (ischange) { changedLines.push(context.line); }
3978 line.stateAfter = context.save();
3979 context.nextLine();
3980 } else {
3981 if (line.text.length <= cm.options.maxHighlightLength)
3982 { processLine(cm, line.text, context); }
3983 line.stateAfter = context.line % 5 == 0 ? context.save() : null;
3984 context.nextLine();
3985 }
3986 if (+new Date > end) {
3987 startWorker(cm, cm.options.workDelay);
3988 return true
3989 }
3990 });
3991 doc.highlightFrontier = context.line;
3992 doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
3993 if (changedLines.length) { runInOp(cm, function () {
3994 for (var i = 0; i < changedLines.length; i++)
3995 { regLineChange(cm, changedLines[i], "text"); }
3996 }); }
3997 }
3998
3999 // DISPLAY DRAWING
4000
4001 var DisplayUpdate = function(cm, viewport, force) {
4002 var display = cm.display;
4003
4004 this.viewport = viewport;
4005 // Store some values that we'll need later (but don't want to force a relayout for)
4006 this.visible = visibleLines(display, cm.doc, viewport);
4007 this.editorIsHidden = !display.wrapper.offsetWidth;
4008 this.wrapperHeight = display.wrapper.clientHeight;
4009 this.wrapperWidth = display.wrapper.clientWidth;
4010 this.oldDisplayWidth = displayWidth(cm);
4011 this.force = force;
4012 this.dims = getDimensions(cm);
4013 this.events = [];
4014 };
4015
4016 DisplayUpdate.prototype.signal = function (emitter, type) {
4017 if (hasHandler(emitter, type))
4018 { this.events.push(arguments); }
4019 };
4020 DisplayUpdate.prototype.finish = function () {
4021 var this$1 = this;
4022
4023 for (var i = 0; i < this.events.length; i++)
4024 { signal.apply(null, this$1.events[i]); }
4025 };
4026
4027 function maybeClipScrollbars(cm) {
4028 var display = cm.display;
4029 if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
4030 display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
4031 display.heightForcer.style.height = scrollGap(cm) + "px";
4032 display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
4033 display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
4034 display.scrollbarsClipped = true;
4035 }
4036 }
4037
4038 function selectionSnapshot(cm) {
4039 if (cm.hasFocus()) { return null }
4040 var active = activeElt();
4041 if (!active || !contains(cm.display.lineDiv, active)) { return null }
4042 var result = {activeElt: active};
4043 if (window.getSelection) {
4044 var sel = window.getSelection();
4045 if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
4046 result.anchorNode = sel.anchorNode;
4047 result.anchorOffset = sel.anchorOffset;
4048 result.focusNode = sel.focusNode;
4049 result.focusOffset = sel.focusOffset;
4050 }
4051 }
4052 return result
4053 }
4054
4055 function restoreSelection(snapshot) {
4056 if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
4057 snapshot.activeElt.focus();
4058 if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
4059 var sel = window.getSelection(), range$$1 = document.createRange();
4060 range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
4061 range$$1.collapse(false);
4062 sel.removeAllRanges();
4063 sel.addRange(range$$1);
4064 sel.extend(snapshot.focusNode, snapshot.focusOffset);
4065 }
4066 }
4067
4068 // Does the actual updating of the line display. Bails out
4069 // (returning false) when there is nothing to be done and forced is
4070 // false.
4071 function updateDisplayIfNeeded(cm, update) {
4072 var display = cm.display, doc = cm.doc;
4073
4074 if (update.editorIsHidden) {
4075 resetView(cm);
4076 return false
4077 }
4078
4079 // Bail out if the visible area is already rendered and nothing changed.
4080 if (!update.force &&
4081 update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
4082 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
4083 display.renderedView == display.view && countDirtyView(cm) == 0)
4084 { return false }
4085
4086 if (maybeUpdateLineNumberWidth(cm)) {
4087 resetView(cm);
4088 update.dims = getDimensions(cm);
4089 }
4090
4091 // Compute a suitable new viewport (from & to)
4092 var end = doc.first + doc.size;
4093 var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
4094 var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
4095 if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
4096 if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
4097 if (sawCollapsedSpans) {
4098 from = visualLineNo(cm.doc, from);
4099 to = visualLineEndNo(cm.doc, to);
4100 }
4101
4102 var different = from != display.viewFrom || to != display.viewTo ||
4103 display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
4104 adjustView(cm, from, to);
4105
4106 display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
4107 // Position the mover div to align with the current scroll position
4108 cm.display.mover.style.top = display.viewOffset + "px";
4109
4110 var toUpdate = countDirtyView(cm);
4111 if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
4112 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
4113 { return false }
4114
4115 // For big changes, we hide the enclosing element during the
4116 // update, since that speeds up the operations on most browsers.
4117 var selSnapshot = selectionSnapshot(cm);
4118 if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
4119 patchDisplay(cm, display.updateLineNumbers, update.dims);
4120 if (toUpdate > 4) { display.lineDiv.style.display = ""; }
4121 display.renderedView = display.view;
4122 // There might have been a widget with a focused element that got
4123 // hidden or updated, if so re-focus it.
4124 restoreSelection(selSnapshot);
4125
4126 // Prevent selection and cursors from interfering with the scroll
4127 // width and height.
4128 removeChildren(display.cursorDiv);
4129 removeChildren(display.selectionDiv);
4130 display.gutters.style.height = display.sizer.style.minHeight = 0;
4131
4132 if (different) {
4133 display.lastWrapHeight = update.wrapperHeight;
4134 display.lastWrapWidth = update.wrapperWidth;
4135 startWorker(cm, 400);
4136 }
4137
4138 display.updateLineNumbers = null;
4139
4140 return true
4141 }
4142
4143 function postUpdateDisplay(cm, update) {
4144 var viewport = update.viewport;
4145
4146 for (var first = true;; first = false) {
4147 if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
4148 // Clip forced viewport to actual scrollable area.
4149 if (viewport && viewport.top != null)
4150 { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
4151 // Updated line heights might result in the drawn area not
4152 // actually covering the viewport. Keep looping until it does.
4153 update.visible = visibleLines(cm.display, cm.doc, viewport);
4154 if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
4155 { break }
4156 }
4157 if (!updateDisplayIfNeeded(cm, update)) { break }
4158 updateHeightsInViewport(cm);
4159 var barMeasure = measureForScrollbars(cm);
4160 updateSelection(cm);
4161 updateScrollbars(cm, barMeasure);
4162 setDocumentHeight(cm, barMeasure);
4163 update.force = false;
4164 }
4165
4166 update.signal(cm, "update", cm);
4167 if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
4168 update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
4169 cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
4170 }
4171 }
4172
4173 function updateDisplaySimple(cm, viewport) {
4174 var update = new DisplayUpdate(cm, viewport);
4175 if (updateDisplayIfNeeded(cm, update)) {
4176 updateHeightsInViewport(cm);
4177 postUpdateDisplay(cm, update);
4178 var barMeasure = measureForScrollbars(cm);
4179 updateSelection(cm);
4180 updateScrollbars(cm, barMeasure);
4181 setDocumentHeight(cm, barMeasure);
4182 update.finish();
4183 }
4184 }
4185
4186 // Sync the actual display DOM structure with display.view, removing
4187 // nodes for lines that are no longer in view, and creating the ones
4188 // that are not there yet, and updating the ones that are out of
4189 // date.
4190 function patchDisplay(cm, updateNumbersFrom, dims) {
4191 var display = cm.display, lineNumbers = cm.options.lineNumbers;
4192 var container = display.lineDiv, cur = container.firstChild;
4193
4194 function rm(node) {
4195 var next = node.nextSibling;
4196 // Works around a throw-scroll bug in OS X Webkit
4197 if (webkit && mac && cm.display.currentWheelTarget == node)
4198 { node.style.display = "none"; }
114 else
4199 else
115 onBlur(this);
4200 { node.parentNode.removeChild(node); }
116
4201 return next
117 for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
4202 }
118 optionHandlers[opt](this, options[opt], Init);
4203
119 maybeUpdateLineNumberWidth(this);
4204 var view = display.view, lineN = display.viewFrom;
120 if (options.finishInit) options.finishInit(this);
4205 // Loop over the elements in the view, syncing cur (the DOM nodes
121 for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
4206 // in display.lineDiv) with the view as we go.
122 endOperation(this);
4207 for (var i = 0; i < view.length; i++) {
123 // Suppress optimizelegibility in Webkit, since it breaks text
4208 var lineView = view[i];
124 // measuring on line wrapping boundaries.
4209 if (lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
125 if (webkit && options.lineWrapping &&
4210 var node = buildLineElement(cm, lineView, lineN, dims);
126 getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
4211 container.insertBefore(node, cur);
127 display.lineDiv.style.textRendering = "auto";
4212 } else { // Already drawn
128 }
4213 while (cur != lineView.node) { cur = rm(cur); }
129
4214 var updateNumber = lineNumbers && updateNumbersFrom != null &&
130 // DISPLAY CONSTRUCTOR
4215 updateNumbersFrom <= lineN && lineView.lineNumber;
4216 if (lineView.changes) {
4217 if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
4218 updateLineForChanges(cm, lineView, lineN, dims);
4219 }
4220 if (updateNumber) {
4221 removeChildren(lineView.lineNumber);
4222 lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
4223 }
4224 cur = lineView.node.nextSibling;
4225 }
4226 lineN += lineView.size;
4227 }
4228 while (cur) { cur = rm(cur); }
4229 }
4230
4231 function updateGutterSpace(display) {
4232 var width = display.gutters.offsetWidth;
4233 display.sizer.style.marginLeft = width + "px";
4234 }
4235
4236 function setDocumentHeight(cm, measure) {
4237 cm.display.sizer.style.minHeight = measure.docHeight + "px";
4238 cm.display.heightForcer.style.top = measure.docHeight + "px";
4239 cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
4240 }
4241
4242 // Re-align line numbers and gutter marks to compensate for
4243 // horizontal scrolling.
4244 function alignHorizontally(cm) {
4245 var display = cm.display, view = display.view;
4246 if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
4247 var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
4248 var gutterW = display.gutters.offsetWidth, left = comp + "px";
4249 for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
4250 if (cm.options.fixedGutter) {
4251 if (view[i].gutter)
4252 { view[i].gutter.style.left = left; }
4253 if (view[i].gutterBackground)
4254 { view[i].gutterBackground.style.left = left; }
4255 }
4256 var align = view[i].alignable;
4257 if (align) { for (var j = 0; j < align.length; j++)
4258 { align[j].style.left = left; } }
4259 } }
4260 if (cm.options.fixedGutter)
4261 { display.gutters.style.left = (comp + gutterW) + "px"; }
4262 }
4263
4264 // Used to ensure that the line number gutter is still the right
4265 // size for the current document size. Returns true when an update
4266 // is needed.
4267 function maybeUpdateLineNumberWidth(cm) {
4268 if (!cm.options.lineNumbers) { return false }
4269 var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
4270 if (last.length != display.lineNumChars) {
4271 var test = display.measure.appendChild(elt("div", [elt("div", last)],
4272 "CodeMirror-linenumber CodeMirror-gutter-elt"));
4273 var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
4274 display.lineGutter.style.width = "";
4275 display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
4276 display.lineNumWidth = display.lineNumInnerWidth + padding;
4277 display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
4278 display.lineGutter.style.width = display.lineNumWidth + "px";
4279 updateGutterSpace(cm.display);
4280 return true
4281 }
4282 return false
4283 }
4284
4285 function getGutters(gutters, lineNumbers) {
4286 var result = [], sawLineNumbers = false;
4287 for (var i = 0; i < gutters.length; i++) {
4288 var name = gutters[i], style = null;
4289 if (typeof name != "string") { style = name.style; name = name.className; }
4290 if (name == "CodeMirror-linenumbers") {
4291 if (!lineNumbers) { continue }
4292 else { sawLineNumbers = true; }
4293 }
4294 result.push({className: name, style: style});
4295 }
4296 if (lineNumbers && !sawLineNumbers) { result.push({className: "CodeMirror-linenumbers", style: null}); }
4297 return result
4298 }
4299
4300 // Rebuild the gutter elements, ensure the margin to the left of the
4301 // code matches their width.
4302 function renderGutters(display) {
4303 var gutters = display.gutters, specs = display.gutterSpecs;
4304 removeChildren(gutters);
4305 display.lineGutter = null;
4306 for (var i = 0; i < specs.length; ++i) {
4307 var ref = specs[i];
4308 var className = ref.className;
4309 var style = ref.style;
4310 var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + className));
4311 if (style) { gElt.style.cssText = style; }
4312 if (className == "CodeMirror-linenumbers") {
4313 display.lineGutter = gElt;
4314 gElt.style.width = (display.lineNumWidth || 1) + "px";
4315 }
4316 }
4317 gutters.style.display = specs.length ? "" : "none";
4318 updateGutterSpace(display);
4319 }
4320
4321 function updateGutters(cm) {
4322 renderGutters(cm.display);
4323 regChange(cm);
4324 alignHorizontally(cm);
4325 }
131
4326
132 // The display handles the DOM integration, both for input reading
4327 // The display handles the DOM integration, both for input reading
133 // and content drawing. It holds references to DOM nodes and
4328 // and content drawing. It holds references to DOM nodes and
134 // display-related state.
4329 // display-related state.
135
4330
136 function Display(place, doc, input) {
4331 function Display(place, doc, input, options) {
137 var d = this;
4332 var d = this;
138 this.input = input;
4333 this.input = input;
139
4334
@@ -145,7 +4340,7 b''
145 d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
4340 d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
146 d.gutterFiller.setAttribute("cm-not-content", "true");
4341 d.gutterFiller.setAttribute("cm-not-content", "true");
147 // Will contain the actual code, positioned to cover the viewport.
4342 // Will contain the actual code, positioned to cover the viewport.
148 d.lineDiv = elt("div", null, "CodeMirror-code");
4343 d.lineDiv = eltP("div", null, "CodeMirror-code");
149 // Elements are added to these to represent selection and cursors.
4344 // Elements are added to these to represent selection and cursors.
150 d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
4345 d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
151 d.cursorDiv = elt("div", null, "CodeMirror-cursors");
4346 d.cursorDiv = elt("div", null, "CodeMirror-cursors");
@@ -154,10 +4349,11 b''
154 // When lines outside of the viewport are measured, they are drawn in this.
4349 // When lines outside of the viewport are measured, they are drawn in this.
155 d.lineMeasure = elt("div", null, "CodeMirror-measure");
4350 d.lineMeasure = elt("div", null, "CodeMirror-measure");
156 // Wraps everything that needs to exist inside the vertically-padded coordinate system
4351 // Wraps everything that needs to exist inside the vertically-padded coordinate system
157 d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
4352 d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
158 null, "position: relative; outline: none");
4353 null, "position: relative; outline: none");
4354 var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
159 // Moved around its parent to cover visible view.
4355 // Moved around its parent to cover visible view.
160 d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
4356 d.mover = elt("div", [lines], null, "position: relative");
161 // Set to the height of the document, allowing scrolling.
4357 // Set to the height of the document, allowing scrolling.
162 d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
4358 d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
163 d.sizerWidth = null;
4359 d.sizerWidth = null;
@@ -176,11 +4372,11 b''
176
4372
177 // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
4373 // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
178 if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
4374 if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
179 if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;
4375 if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
180
4376
181 if (place) {
4377 if (place) {
182 if (place.appendChild) place.appendChild(d.wrapper);
4378 if (place.appendChild) { place.appendChild(d.wrapper); }
183 else place(d.wrapper);
4379 else { place(d.wrapper); }
184 }
4380 }
185
4381
186 // Current rendered range (may be bigger than the view window).
4382 // Current rendered range (may be bigger than the view window).
@@ -228,3738 +4424,12 b''
228
4424
229 d.activeTouch = null;
4425 d.activeTouch = null;
230
4426
4427 d.gutterSpecs = getGutters(options.gutters, options.lineNumbers);
4428 renderGutters(d);
4429
231 input.init(d);
4430 input.init(d);
232 }
4431 }
233
4432
234 // STATE UPDATES
235
236 // Used to get the editor into a consistent state again when options change.
237
238 function loadMode(cm) {
239 cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
240 resetModeState(cm);
241 }
242
243 function resetModeState(cm) {
244 cm.doc.iter(function(line) {
245 if (line.stateAfter) line.stateAfter = null;
246 if (line.styles) line.styles = null;
247 });
248 cm.doc.frontier = cm.doc.first;
249 startWorker(cm, 100);
250 cm.state.modeGen++;
251 if (cm.curOp) regChange(cm);
252 }
253
254 function wrappingChanged(cm) {
255 if (cm.options.lineWrapping) {
256 addClass(cm.display.wrapper, "CodeMirror-wrap");
257 cm.display.sizer.style.minWidth = "";
258 cm.display.sizerWidth = null;
259 } else {
260 rmClass(cm.display.wrapper, "CodeMirror-wrap");
261 findMaxLine(cm);
262 }
263 estimateLineHeights(cm);
264 regChange(cm);
265 clearCaches(cm);
266 setTimeout(function(){updateScrollbars(cm);}, 100);
267 }
268
269 // Returns a function that estimates the height of a line, to use as
270 // first approximation until the line becomes visible (and is thus
271 // properly measurable).
272 function estimateHeight(cm) {
273 var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
274 var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
275 return function(line) {
276 if (lineIsHidden(cm.doc, line)) return 0;
277
278 var widgetsHeight = 0;
279 if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
280 if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
281 }
282
283 if (wrapping)
284 return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
285 else
286 return widgetsHeight + th;
287 };
288 }
289
290 function estimateLineHeights(cm) {
291 var doc = cm.doc, est = estimateHeight(cm);
292 doc.iter(function(line) {
293 var estHeight = est(line);
294 if (estHeight != line.height) updateLineHeight(line, estHeight);
295 });
296 }
297
298 function themeChanged(cm) {
299 cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
300 cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
301 clearCaches(cm);
302 }
303
304 function guttersChanged(cm) {
305 updateGutters(cm);
306 regChange(cm);
307 setTimeout(function(){alignHorizontally(cm);}, 20);
308 }
309
310 // Rebuild the gutter elements, ensure the margin to the left of the
311 // code matches their width.
312 function updateGutters(cm) {
313 var gutters = cm.display.gutters, specs = cm.options.gutters;
314 removeChildren(gutters);
315 for (var i = 0; i < specs.length; ++i) {
316 var gutterClass = specs[i];
317 var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
318 if (gutterClass == "CodeMirror-linenumbers") {
319 cm.display.lineGutter = gElt;
320 gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
321 }
322 }
323 gutters.style.display = i ? "" : "none";
324 updateGutterSpace(cm);
325 }
326
327 function updateGutterSpace(cm) {
328 var width = cm.display.gutters.offsetWidth;
329 cm.display.sizer.style.marginLeft = width + "px";
330 }
331
332 // Compute the character length of a line, taking into account
333 // collapsed ranges (see markText) that might hide parts, and join
334 // other lines onto it.
335 function lineLength(line) {
336 if (line.height == 0) return 0;
337 var len = line.text.length, merged, cur = line;
338 while (merged = collapsedSpanAtStart(cur)) {
339 var found = merged.find(0, true);
340 cur = found.from.line;
341 len += found.from.ch - found.to.ch;
342 }
343 cur = line;
344 while (merged = collapsedSpanAtEnd(cur)) {
345 var found = merged.find(0, true);
346 len -= cur.text.length - found.from.ch;
347 cur = found.to.line;
348 len += cur.text.length - found.to.ch;
349 }
350 return len;
351 }
352
353 // Find the longest line in the document.
354 function findMaxLine(cm) {
355 var d = cm.display, doc = cm.doc;
356 d.maxLine = getLine(doc, doc.first);
357 d.maxLineLength = lineLength(d.maxLine);
358 d.maxLineChanged = true;
359 doc.iter(function(line) {
360 var len = lineLength(line);
361 if (len > d.maxLineLength) {
362 d.maxLineLength = len;
363 d.maxLine = line;
364 }
365 });
366 }
367
368 // Make sure the gutters options contains the element
369 // "CodeMirror-linenumbers" when the lineNumbers option is true.
370 function setGuttersForLineNumbers(options) {
371 var found = indexOf(options.gutters, "CodeMirror-linenumbers");
372 if (found == -1 && options.lineNumbers) {
373 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
374 } else if (found > -1 && !options.lineNumbers) {
375 options.gutters = options.gutters.slice(0);
376 options.gutters.splice(found, 1);
377 }
378 }
379
380 // SCROLLBARS
381
382 // Prepare DOM reads needed to update the scrollbars. Done in one
383 // shot to minimize update/measure roundtrips.
384 function measureForScrollbars(cm) {
385 var d = cm.display, gutterW = d.gutters.offsetWidth;
386 var docH = Math.round(cm.doc.height + paddingVert(cm.display));
387 return {
388 clientHeight: d.scroller.clientHeight,
389 viewHeight: d.wrapper.clientHeight,
390 scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
391 viewWidth: d.wrapper.clientWidth,
392 barLeft: cm.options.fixedGutter ? gutterW : 0,
393 docHeight: docH,
394 scrollHeight: docH + scrollGap(cm) + d.barHeight,
395 nativeBarWidth: d.nativeBarWidth,
396 gutterWidth: gutterW
397 };
398 }
399
400 function NativeScrollbars(place, scroll, cm) {
401 this.cm = cm;
402 var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
403 var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
404 place(vert); place(horiz);
405
406 on(vert, "scroll", function() {
407 if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
408 });
409 on(horiz, "scroll", function() {
410 if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
411 });
412
413 this.checkedZeroWidth = false;
414 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
415 if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
416 }
417
418 NativeScrollbars.prototype = copyObj({
419 update: function(measure) {
420 var needsH = measure.scrollWidth > measure.clientWidth + 1;
421 var needsV = measure.scrollHeight > measure.clientHeight + 1;
422 var sWidth = measure.nativeBarWidth;
423
424 if (needsV) {
425 this.vert.style.display = "block";
426 this.vert.style.bottom = needsH ? sWidth + "px" : "0";
427 var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
428 // A bug in IE8 can cause this value to be negative, so guard it.
429 this.vert.firstChild.style.height =
430 Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
431 } else {
432 this.vert.style.display = "";
433 this.vert.firstChild.style.height = "0";
434 }
435
436 if (needsH) {
437 this.horiz.style.display = "block";
438 this.horiz.style.right = needsV ? sWidth + "px" : "0";
439 this.horiz.style.left = measure.barLeft + "px";
440 var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
441 this.horiz.firstChild.style.width =
442 (measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
443 } else {
444 this.horiz.style.display = "";
445 this.horiz.firstChild.style.width = "0";
446 }
447
448 if (!this.checkedZeroWidth && measure.clientHeight > 0) {
449 if (sWidth == 0) this.zeroWidthHack();
450 this.checkedZeroWidth = true;
451 }
452
453 return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
454 },
455 setScrollLeft: function(pos) {
456 if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
457 if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
458 },
459 setScrollTop: function(pos) {
460 if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
461 if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);
462 },
463 zeroWidthHack: function() {
464 var w = mac && !mac_geMountainLion ? "12px" : "18px";
465 this.horiz.style.height = this.vert.style.width = w;
466 this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
467 this.disableHoriz = new Delayed;
468 this.disableVert = new Delayed;
469 },
470 enableZeroWidthBar: function(bar, delay) {
471 bar.style.pointerEvents = "auto";
472 function maybeDisable() {
473 // To find out whether the scrollbar is still visible, we
474 // check whether the element under the pixel in the bottom
475 // left corner of the scrollbar box is the scrollbar box
476 // itself (when the bar is still visible) or its filler child
477 // (when the bar is hidden). If it is still visible, we keep
478 // it enabled, if it's hidden, we disable pointer events.
479 var box = bar.getBoundingClientRect();
480 var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);
481 if (elt != bar) bar.style.pointerEvents = "none";
482 else delay.set(1000, maybeDisable);
483 }
484 delay.set(1000, maybeDisable);
485 },
486 clear: function() {
487 var parent = this.horiz.parentNode;
488 parent.removeChild(this.horiz);
489 parent.removeChild(this.vert);
490 }
491 }, NativeScrollbars.prototype);
492
493 function NullScrollbars() {}
494
495 NullScrollbars.prototype = copyObj({
496 update: function() { return {bottom: 0, right: 0}; },
497 setScrollLeft: function() {},
498 setScrollTop: function() {},
499 clear: function() {}
500 }, NullScrollbars.prototype);
501
502 CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
503
504 function initScrollbars(cm) {
505 if (cm.display.scrollbars) {
506 cm.display.scrollbars.clear();
507 if (cm.display.scrollbars.addClass)
508 rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
509 }
510
511 cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
512 cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
513 // Prevent clicks in the scrollbars from killing focus
514 on(node, "mousedown", function() {
515 if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);
516 });
517 node.setAttribute("cm-not-content", "true");
518 }, function(pos, axis) {
519 if (axis == "horizontal") setScrollLeft(cm, pos);
520 else setScrollTop(cm, pos);
521 }, cm);
522 if (cm.display.scrollbars.addClass)
523 addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
524 }
525
526 function updateScrollbars(cm, measure) {
527 if (!measure) measure = measureForScrollbars(cm);
528 var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
529 updateScrollbarsInner(cm, measure);
530 for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
531 if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
532 updateHeightsInViewport(cm);
533 updateScrollbarsInner(cm, measureForScrollbars(cm));
534 startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
535 }
536 }
537
538 // Re-synchronize the fake scrollbars with the actual size of the
539 // content.
540 function updateScrollbarsInner(cm, measure) {
541 var d = cm.display;
542 var sizes = d.scrollbars.update(measure);
543
544 d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
545 d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
546
547 if (sizes.right && sizes.bottom) {
548 d.scrollbarFiller.style.display = "block";
549 d.scrollbarFiller.style.height = sizes.bottom + "px";
550 d.scrollbarFiller.style.width = sizes.right + "px";
551 } else d.scrollbarFiller.style.display = "";
552 if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
553 d.gutterFiller.style.display = "block";
554 d.gutterFiller.style.height = sizes.bottom + "px";
555 d.gutterFiller.style.width = measure.gutterWidth + "px";
556 } else d.gutterFiller.style.display = "";
557 }
558
559 // Compute the lines that are visible in a given viewport (defaults
560 // the the current scroll position). viewport may contain top,
561 // height, and ensure (see op.scrollToPos) properties.
562 function visibleLines(display, doc, viewport) {
563 var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
564 top = Math.floor(top - paddingTop(display));
565 var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
566
567 var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
568 // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
569 // forces those lines into the viewport (if possible).
570 if (viewport && viewport.ensure) {
571 var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
572 if (ensureFrom < from) {
573 from = ensureFrom;
574 to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
575 } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
576 from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
577 to = ensureTo;
578 }
579 }
580 return {from: from, to: Math.max(to, from + 1)};
581 }
582
583 // LINE NUMBERS
584
585 // Re-align line numbers and gutter marks to compensate for
586 // horizontal scrolling.
587 function alignHorizontally(cm) {
588 var display = cm.display, view = display.view;
589 if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
590 var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
591 var gutterW = display.gutters.offsetWidth, left = comp + "px";
592 for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
593 if (cm.options.fixedGutter && view[i].gutter)
594 view[i].gutter.style.left = left;
595 var align = view[i].alignable;
596 if (align) for (var j = 0; j < align.length; j++)
597 align[j].style.left = left;
598 }
599 if (cm.options.fixedGutter)
600 display.gutters.style.left = (comp + gutterW) + "px";
601 }
602
603 // Used to ensure that the line number gutter is still the right
604 // size for the current document size. Returns true when an update
605 // is needed.
606 function maybeUpdateLineNumberWidth(cm) {
607 if (!cm.options.lineNumbers) return false;
608 var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
609 if (last.length != display.lineNumChars) {
610 var test = display.measure.appendChild(elt("div", [elt("div", last)],
611 "CodeMirror-linenumber CodeMirror-gutter-elt"));
612 var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
613 display.lineGutter.style.width = "";
614 display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
615 display.lineNumWidth = display.lineNumInnerWidth + padding;
616 display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
617 display.lineGutter.style.width = display.lineNumWidth + "px";
618 updateGutterSpace(cm);
619 return true;
620 }
621 return false;
622 }
623
624 function lineNumberFor(options, i) {
625 return String(options.lineNumberFormatter(i + options.firstLineNumber));
626 }
627
628 // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
629 // but using getBoundingClientRect to get a sub-pixel-accurate
630 // result.
631 function compensateForHScroll(display) {
632 return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
633 }
634
635 // DISPLAY DRAWING
636
637 function DisplayUpdate(cm, viewport, force) {
638 var display = cm.display;
639
640 this.viewport = viewport;
641 // Store some values that we'll need later (but don't want to force a relayout for)
642 this.visible = visibleLines(display, cm.doc, viewport);
643 this.editorIsHidden = !display.wrapper.offsetWidth;
644 this.wrapperHeight = display.wrapper.clientHeight;
645 this.wrapperWidth = display.wrapper.clientWidth;
646 this.oldDisplayWidth = displayWidth(cm);
647 this.force = force;
648 this.dims = getDimensions(cm);
649 this.events = [];
650 }
651
652 DisplayUpdate.prototype.signal = function(emitter, type) {
653 if (hasHandler(emitter, type))
654 this.events.push(arguments);
655 };
656 DisplayUpdate.prototype.finish = function() {
657 for (var i = 0; i < this.events.length; i++)
658 signal.apply(null, this.events[i]);
659 };
660
661 function maybeClipScrollbars(cm) {
662 var display = cm.display;
663 if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
664 display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
665 display.heightForcer.style.height = scrollGap(cm) + "px";
666 display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
667 display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
668 display.scrollbarsClipped = true;
669 }
670 }
671
672 // Does the actual updating of the line display. Bails out
673 // (returning false) when there is nothing to be done and forced is
674 // false.
675 function updateDisplayIfNeeded(cm, update) {
676 var display = cm.display, doc = cm.doc;
677
678 if (update.editorIsHidden) {
679 resetView(cm);
680 return false;
681 }
682
683 // Bail out if the visible area is already rendered and nothing changed.
684 if (!update.force &&
685 update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
686 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
687 display.renderedView == display.view && countDirtyView(cm) == 0)
688 return false;
689
690 if (maybeUpdateLineNumberWidth(cm)) {
691 resetView(cm);
692 update.dims = getDimensions(cm);
693 }
694
695 // Compute a suitable new viewport (from & to)
696 var end = doc.first + doc.size;
697 var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
698 var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
699 if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
700 if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
701 if (sawCollapsedSpans) {
702 from = visualLineNo(cm.doc, from);
703 to = visualLineEndNo(cm.doc, to);
704 }
705
706 var different = from != display.viewFrom || to != display.viewTo ||
707 display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
708 adjustView(cm, from, to);
709
710 display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
711 // Position the mover div to align with the current scroll position
712 cm.display.mover.style.top = display.viewOffset + "px";
713
714 var toUpdate = countDirtyView(cm);
715 if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
716 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
717 return false;
718
719 // For big changes, we hide the enclosing element during the
720 // update, since that speeds up the operations on most browsers.
721 var focused = activeElt();
722 if (toUpdate > 4) display.lineDiv.style.display = "none";
723 patchDisplay(cm, display.updateLineNumbers, update.dims);
724 if (toUpdate > 4) display.lineDiv.style.display = "";
725 display.renderedView = display.view;
726 // There might have been a widget with a focused element that got
727 // hidden or updated, if so re-focus it.
728 if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
729
730 // Prevent selection and cursors from interfering with the scroll
731 // width and height.
732 removeChildren(display.cursorDiv);
733 removeChildren(display.selectionDiv);
734 display.gutters.style.height = display.sizer.style.minHeight = 0;
735
736 if (different) {
737 display.lastWrapHeight = update.wrapperHeight;
738 display.lastWrapWidth = update.wrapperWidth;
739 startWorker(cm, 400);
740 }
741
742 display.updateLineNumbers = null;
743
744 return true;
745 }
746
747 function postUpdateDisplay(cm, update) {
748 var viewport = update.viewport;
749 for (var first = true;; first = false) {
750 if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
751 // Clip forced viewport to actual scrollable area.
752 if (viewport && viewport.top != null)
753 viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
754 // Updated line heights might result in the drawn area not
755 // actually covering the viewport. Keep looping until it does.
756 update.visible = visibleLines(cm.display, cm.doc, viewport);
757 if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
758 break;
759 }
760 if (!updateDisplayIfNeeded(cm, update)) break;
761 updateHeightsInViewport(cm);
762 var barMeasure = measureForScrollbars(cm);
763 updateSelection(cm);
764 setDocumentHeight(cm, barMeasure);
765 updateScrollbars(cm, barMeasure);
766 }
767
768 update.signal(cm, "update", cm);
769 if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
770 update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
771 cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
772 }
773 }
774
775 function updateDisplaySimple(cm, viewport) {
776 var update = new DisplayUpdate(cm, viewport);
777 if (updateDisplayIfNeeded(cm, update)) {
778 updateHeightsInViewport(cm);
779 postUpdateDisplay(cm, update);
780 var barMeasure = measureForScrollbars(cm);
781 updateSelection(cm);
782 setDocumentHeight(cm, barMeasure);
783 updateScrollbars(cm, barMeasure);
784 update.finish();
785 }
786 }
787
788 function setDocumentHeight(cm, measure) {
789 cm.display.sizer.style.minHeight = measure.docHeight + "px";
790 var total = measure.docHeight + cm.display.barHeight;
791 cm.display.heightForcer.style.top = total + "px";
792 cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
793 }
794
795 // Read the actual heights of the rendered lines, and update their
796 // stored heights to match.
797 function updateHeightsInViewport(cm) {
798 var display = cm.display;
799 var prevBottom = display.lineDiv.offsetTop;
800 for (var i = 0; i < display.view.length; i++) {
801 var cur = display.view[i], height;
802 if (cur.hidden) continue;
803 if (ie && ie_version < 8) {
804 var bot = cur.node.offsetTop + cur.node.offsetHeight;
805 height = bot - prevBottom;
806 prevBottom = bot;
807 } else {
808 var box = cur.node.getBoundingClientRect();
809 height = box.bottom - box.top;
810 }
811 var diff = cur.line.height - height;
812 if (height < 2) height = textHeight(display);
813 if (diff > .001 || diff < -.001) {
814 updateLineHeight(cur.line, height);
815 updateWidgetHeight(cur.line);
816 if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
817 updateWidgetHeight(cur.rest[j]);
818 }
819 }
820 }
821
822 // Read and store the height of line widgets associated with the
823 // given line.
824 function updateWidgetHeight(line) {
825 if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
826 line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;
827 }
828
829 // Do a bulk-read of the DOM positions and sizes needed to draw the
830 // view, so that we don't interleave reading and writing to the DOM.
831 function getDimensions(cm) {
832 var d = cm.display, left = {}, width = {};
833 var gutterLeft = d.gutters.clientLeft;
834 for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
835 left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
836 width[cm.options.gutters[i]] = n.clientWidth;
837 }
838 return {fixedPos: compensateForHScroll(d),
839 gutterTotalWidth: d.gutters.offsetWidth,
840 gutterLeft: left,
841 gutterWidth: width,
842 wrapperWidth: d.wrapper.clientWidth};
843 }
844
845 // Sync the actual display DOM structure with display.view, removing
846 // nodes for lines that are no longer in view, and creating the ones
847 // that are not there yet, and updating the ones that are out of
848 // date.
849 function patchDisplay(cm, updateNumbersFrom, dims) {
850 var display = cm.display, lineNumbers = cm.options.lineNumbers;
851 var container = display.lineDiv, cur = container.firstChild;
852
853 function rm(node) {
854 var next = node.nextSibling;
855 // Works around a throw-scroll bug in OS X Webkit
856 if (webkit && mac && cm.display.currentWheelTarget == node)
857 node.style.display = "none";
858 else
859 node.parentNode.removeChild(node);
860 return next;
861 }
862
863 var view = display.view, lineN = display.viewFrom;
864 // Loop over the elements in the view, syncing cur (the DOM nodes
865 // in display.lineDiv) with the view as we go.
866 for (var i = 0; i < view.length; i++) {
867 var lineView = view[i];
868 if (lineView.hidden) {
869 } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
870 var node = buildLineElement(cm, lineView, lineN, dims);
871 container.insertBefore(node, cur);
872 } else { // Already drawn
873 while (cur != lineView.node) cur = rm(cur);
874 var updateNumber = lineNumbers && updateNumbersFrom != null &&
875 updateNumbersFrom <= lineN && lineView.lineNumber;
876 if (lineView.changes) {
877 if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
878 updateLineForChanges(cm, lineView, lineN, dims);
879 }
880 if (updateNumber) {
881 removeChildren(lineView.lineNumber);
882 lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
883 }
884 cur = lineView.node.nextSibling;
885 }
886 lineN += lineView.size;
887 }
888 while (cur) cur = rm(cur);
889 }
890
891 // When an aspect of a line changes, a string is added to
892 // lineView.changes. This updates the relevant part of the line's
893 // DOM structure.
894 function updateLineForChanges(cm, lineView, lineN, dims) {
895 for (var j = 0; j < lineView.changes.length; j++) {
896 var type = lineView.changes[j];
897 if (type == "text") updateLineText(cm, lineView);
898 else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
899 else if (type == "class") updateLineClasses(lineView);
900 else if (type == "widget") updateLineWidgets(cm, lineView, dims);
901 }
902 lineView.changes = null;
903 }
904
905 // Lines with gutter elements, widgets or a background class need to
906 // be wrapped, and have the extra elements added to the wrapper div
907 function ensureLineWrapped(lineView) {
908 if (lineView.node == lineView.text) {
909 lineView.node = elt("div", null, null, "position: relative");
910 if (lineView.text.parentNode)
911 lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
912 lineView.node.appendChild(lineView.text);
913 if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
914 }
915 return lineView.node;
916 }
917
918 function updateLineBackground(lineView) {
919 var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
920 if (cls) cls += " CodeMirror-linebackground";
921 if (lineView.background) {
922 if (cls) lineView.background.className = cls;
923 else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
924 } else if (cls) {
925 var wrap = ensureLineWrapped(lineView);
926 lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
927 }
928 }
929
930 // Wrapper around buildLineContent which will reuse the structure
931 // in display.externalMeasured when possible.
932 function getLineContent(cm, lineView) {
933 var ext = cm.display.externalMeasured;
934 if (ext && ext.line == lineView.line) {
935 cm.display.externalMeasured = null;
936 lineView.measure = ext.measure;
937 return ext.built;
938 }
939 return buildLineContent(cm, lineView);
940 }
941
942 // Redraw the line's text. Interacts with the background and text
943 // classes because the mode may output tokens that influence these
944 // classes.
945 function updateLineText(cm, lineView) {
946 var cls = lineView.text.className;
947 var built = getLineContent(cm, lineView);
948 if (lineView.text == lineView.node) lineView.node = built.pre;
949 lineView.text.parentNode.replaceChild(built.pre, lineView.text);
950 lineView.text = built.pre;
951 if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
952 lineView.bgClass = built.bgClass;
953 lineView.textClass = built.textClass;
954 updateLineClasses(lineView);
955 } else if (cls) {
956 lineView.text.className = cls;
957 }
958 }
959
960 function updateLineClasses(lineView) {
961 updateLineBackground(lineView);
962 if (lineView.line.wrapClass)
963 ensureLineWrapped(lineView).className = lineView.line.wrapClass;
964 else if (lineView.node != lineView.text)
965 lineView.node.className = "";
966 var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
967 lineView.text.className = textClass || "";
968 }
969
970 function updateLineGutter(cm, lineView, lineN, dims) {
971 if (lineView.gutter) {
972 lineView.node.removeChild(lineView.gutter);
973 lineView.gutter = null;
974 }
975 if (lineView.gutterBackground) {
976 lineView.node.removeChild(lineView.gutterBackground);
977 lineView.gutterBackground = null;
978 }
979 if (lineView.line.gutterClass) {
980 var wrap = ensureLineWrapped(lineView);
981 lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
982 "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
983 "px; width: " + dims.gutterTotalWidth + "px");
984 wrap.insertBefore(lineView.gutterBackground, lineView.text);
985 }
986 var markers = lineView.line.gutterMarkers;
987 if (cm.options.lineNumbers || markers) {
988 var wrap = ensureLineWrapped(lineView);
989 var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
990 (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px");
991 cm.display.input.setUneditable(gutterWrap);
992 wrap.insertBefore(gutterWrap, lineView.text);
993 if (lineView.line.gutterClass)
994 gutterWrap.className += " " + lineView.line.gutterClass;
995 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
996 lineView.lineNumber = gutterWrap.appendChild(
997 elt("div", lineNumberFor(cm.options, lineN),
998 "CodeMirror-linenumber CodeMirror-gutter-elt",
999 "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
1000 + cm.display.lineNumInnerWidth + "px"));
1001 if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
1002 var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
1003 if (found)
1004 gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
1005 dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
1006 }
1007 }
1008 }
1009
1010 function updateLineWidgets(cm, lineView, dims) {
1011 if (lineView.alignable) lineView.alignable = null;
1012 for (var node = lineView.node.firstChild, next; node; node = next) {
1013 var next = node.nextSibling;
1014 if (node.className == "CodeMirror-linewidget")
1015 lineView.node.removeChild(node);
1016 }
1017 insertLineWidgets(cm, lineView, dims);
1018 }
1019
1020 // Build a line's DOM representation from scratch
1021 function buildLineElement(cm, lineView, lineN, dims) {
1022 var built = getLineContent(cm, lineView);
1023 lineView.text = lineView.node = built.pre;
1024 if (built.bgClass) lineView.bgClass = built.bgClass;
1025 if (built.textClass) lineView.textClass = built.textClass;
1026
1027 updateLineClasses(lineView);
1028 updateLineGutter(cm, lineView, lineN, dims);
1029 insertLineWidgets(cm, lineView, dims);
1030 return lineView.node;
1031 }
1032
1033 // A lineView may contain multiple logical lines (when merged by
1034 // collapsed spans). The widgets for all of them need to be drawn.
1035 function insertLineWidgets(cm, lineView, dims) {
1036 insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
1037 if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
1038 insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
1039 }
1040
1041 function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
1042 if (!line.widgets) return;
1043 var wrap = ensureLineWrapped(lineView);
1044 for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
1045 var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
1046 if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
1047 positionLineWidget(widget, node, lineView, dims);
1048 cm.display.input.setUneditable(node);
1049 if (allowAbove && widget.above)
1050 wrap.insertBefore(node, lineView.gutter || lineView.text);
1051 else
1052 wrap.appendChild(node);
1053 signalLater(widget, "redraw");
1054 }
1055 }
1056
1057 function positionLineWidget(widget, node, lineView, dims) {
1058 if (widget.noHScroll) {
1059 (lineView.alignable || (lineView.alignable = [])).push(node);
1060 var width = dims.wrapperWidth;
1061 node.style.left = dims.fixedPos + "px";
1062 if (!widget.coverGutter) {
1063 width -= dims.gutterTotalWidth;
1064 node.style.paddingLeft = dims.gutterTotalWidth + "px";
1065 }
1066 node.style.width = width + "px";
1067 }
1068 if (widget.coverGutter) {
1069 node.style.zIndex = 5;
1070 node.style.position = "relative";
1071 if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
1072 }
1073 }
1074
1075 // POSITION OBJECT
1076
1077 // A Pos instance represents a position within the text.
1078 var Pos = CodeMirror.Pos = function(line, ch) {
1079 if (!(this instanceof Pos)) return new Pos(line, ch);
1080 this.line = line; this.ch = ch;
1081 };
1082
1083 // Compare two positions, return 0 if they are the same, a negative
1084 // number when a is less, and a positive number otherwise.
1085 var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
1086
1087 function copyPos(x) {return Pos(x.line, x.ch);}
1088 function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
1089 function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
1090
1091 // INPUT HANDLING
1092
1093 function ensureFocus(cm) {
1094 if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
1095 }
1096
1097 // This will be set to an array of strings when copying, so that,
1098 // when pasting, we know what kind of selections the copied text
1099 // was made out of.
1100 var lastCopied = null;
1101
1102 function applyTextInput(cm, inserted, deleted, sel, origin) {
1103 var doc = cm.doc;
1104 cm.display.shift = false;
1105 if (!sel) sel = doc.sel;
1106
1107 var paste = cm.state.pasteIncoming || origin == "paste";
1108 var textLines = doc.splitLines(inserted), multiPaste = null;
1109 // When pasing N lines into N selections, insert one line per selection
1110 if (paste && sel.ranges.length > 1) {
1111 if (lastCopied && lastCopied.join("\n") == inserted) {
1112 if (sel.ranges.length % lastCopied.length == 0) {
1113 multiPaste = [];
1114 for (var i = 0; i < lastCopied.length; i++)
1115 multiPaste.push(doc.splitLines(lastCopied[i]));
1116 }
1117 } else if (textLines.length == sel.ranges.length) {
1118 multiPaste = map(textLines, function(l) { return [l]; });
1119 }
1120 }
1121
1122 // Normal behavior is to insert the new text into every selection
1123 for (var i = sel.ranges.length - 1; i >= 0; i--) {
1124 var range = sel.ranges[i];
1125 var from = range.from(), to = range.to();
1126 if (range.empty()) {
1127 if (deleted && deleted > 0) // Handle deletion
1128 from = Pos(from.line, from.ch - deleted);
1129 else if (cm.state.overwrite && !paste) // Handle overwrite
1130 to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
1131 }
1132 var updateInput = cm.curOp.updateInput;
1133 var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
1134 origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
1135 makeChange(cm.doc, changeEvent);
1136 signalLater(cm, "inputRead", cm, changeEvent);
1137 }
1138 if (inserted && !paste)
1139 triggerElectric(cm, inserted);
1140
1141 ensureCursorVisible(cm);
1142 cm.curOp.updateInput = updateInput;
1143 cm.curOp.typing = true;
1144 cm.state.pasteIncoming = cm.state.cutIncoming = false;
1145 }
1146
1147 function handlePaste(e, cm) {
1148 var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
1149 if (pasted) {
1150 e.preventDefault();
1151 if (!cm.isReadOnly() && !cm.options.disableInput)
1152 runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
1153 return true;
1154 }
1155 }
1156
1157 function triggerElectric(cm, inserted) {
1158 // When an 'electric' character is inserted, immediately trigger a reindent
1159 if (!cm.options.electricChars || !cm.options.smartIndent) return;
1160 var sel = cm.doc.sel;
1161
1162 for (var i = sel.ranges.length - 1; i >= 0; i--) {
1163 var range = sel.ranges[i];
1164 if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue;
1165 var mode = cm.getModeAt(range.head);
1166 var indented = false;
1167 if (mode.electricChars) {
1168 for (var j = 0; j < mode.electricChars.length; j++)
1169 if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
1170 indented = indentLine(cm, range.head.line, "smart");
1171 break;
1172 }
1173 } else if (mode.electricInput) {
1174 if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
1175 indented = indentLine(cm, range.head.line, "smart");
1176 }
1177 if (indented) signalLater(cm, "electricInput", cm, range.head.line);
1178 }
1179 }
1180
1181 function copyableRanges(cm) {
1182 var text = [], ranges = [];
1183 for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
1184 var line = cm.doc.sel.ranges[i].head.line;
1185 var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
1186 ranges.push(lineRange);
1187 text.push(cm.getRange(lineRange.anchor, lineRange.head));
1188 }
1189 return {text: text, ranges: ranges};
1190 }
1191
1192 function disableBrowserMagic(field) {
1193 field.setAttribute("autocorrect", "off");
1194 field.setAttribute("autocapitalize", "off");
1195 field.setAttribute("spellcheck", "false");
1196 }
1197
1198 // TEXTAREA INPUT STYLE
1199
1200 function TextareaInput(cm) {
1201 this.cm = cm;
1202 // See input.poll and input.reset
1203 this.prevInput = "";
1204
1205 // Flag that indicates whether we expect input to appear real soon
1206 // now (after some event like 'keypress' or 'input') and are
1207 // polling intensively.
1208 this.pollingFast = false;
1209 // Self-resetting timeout for the poller
1210 this.polling = new Delayed();
1211 // Tracks when input.reset has punted to just putting a short
1212 // string into the textarea instead of the full selection.
1213 this.inaccurateSelection = false;
1214 // Used to work around IE issue with selection being forgotten when focus moves away from textarea
1215 this.hasSelection = false;
1216 this.composing = null;
1217 };
1218
1219 function hiddenTextarea() {
1220 var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
1221 var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
1222 // The textarea is kept positioned near the cursor to prevent the
1223 // fact that it'll be scrolled into view on input from scrolling
1224 // our fake cursor out of view. On webkit, when wrap=off, paste is
1225 // very slow. So make the area wide instead.
1226 if (webkit) te.style.width = "1000px";
1227 else te.setAttribute("wrap", "off");
1228 // If border: 0; -- iOS fails to open keyboard (issue #1287)
1229 if (ios) te.style.border = "1px solid black";
1230 disableBrowserMagic(te);
1231 return div;
1232 }
1233
1234 TextareaInput.prototype = copyObj({
1235 init: function(display) {
1236 var input = this, cm = this.cm;
1237
1238 // Wraps and hides input textarea
1239 var div = this.wrapper = hiddenTextarea();
1240 // The semihidden textarea that is focused when the editor is
1241 // focused, and receives input.
1242 var te = this.textarea = div.firstChild;
1243 display.wrapper.insertBefore(div, display.wrapper.firstChild);
1244
1245 // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
1246 if (ios) te.style.width = "0px";
1247
1248 on(te, "input", function() {
1249 if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;
1250 input.poll();
1251 });
1252
1253 on(te, "paste", function(e) {
1254 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return
1255
1256 cm.state.pasteIncoming = true;
1257 input.fastPoll();
1258 });
1259
1260 function prepareCopyCut(e) {
1261 if (signalDOMEvent(cm, e)) return
1262 if (cm.somethingSelected()) {
1263 lastCopied = cm.getSelections();
1264 if (input.inaccurateSelection) {
1265 input.prevInput = "";
1266 input.inaccurateSelection = false;
1267 te.value = lastCopied.join("\n");
1268 selectInput(te);
1269 }
1270 } else if (!cm.options.lineWiseCopyCut) {
1271 return;
1272 } else {
1273 var ranges = copyableRanges(cm);
1274 lastCopied = ranges.text;
1275 if (e.type == "cut") {
1276 cm.setSelections(ranges.ranges, null, sel_dontScroll);
1277 } else {
1278 input.prevInput = "";
1279 te.value = ranges.text.join("\n");
1280 selectInput(te);
1281 }
1282 }
1283 if (e.type == "cut") cm.state.cutIncoming = true;
1284 }
1285 on(te, "cut", prepareCopyCut);
1286 on(te, "copy", prepareCopyCut);
1287
1288 on(display.scroller, "paste", function(e) {
1289 if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return;
1290 cm.state.pasteIncoming = true;
1291 input.focus();
1292 });
1293
1294 // Prevent normal selection in the editor (we handle our own)
1295 on(display.lineSpace, "selectstart", function(e) {
1296 if (!eventInWidget(display, e)) e_preventDefault(e);
1297 });
1298
1299 on(te, "compositionstart", function() {
1300 var start = cm.getCursor("from");
1301 if (input.composing) input.composing.range.clear()
1302 input.composing = {
1303 start: start,
1304 range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
1305 };
1306 });
1307 on(te, "compositionend", function() {
1308 if (input.composing) {
1309 input.poll();
1310 input.composing.range.clear();
1311 input.composing = null;
1312 }
1313 });
1314 },
1315
1316 prepareSelection: function() {
1317 // Redraw the selection and/or cursor
1318 var cm = this.cm, display = cm.display, doc = cm.doc;
1319 var result = prepareSelection(cm);
1320
1321 // Move the hidden textarea near the cursor to prevent scrolling artifacts
1322 if (cm.options.moveInputWithCursor) {
1323 var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
1324 var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
1325 result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
1326 headPos.top + lineOff.top - wrapOff.top));
1327 result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
1328 headPos.left + lineOff.left - wrapOff.left));
1329 }
1330
1331 return result;
1332 },
1333
1334 showSelection: function(drawn) {
1335 var cm = this.cm, display = cm.display;
1336 removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
1337 removeChildrenAndAdd(display.selectionDiv, drawn.selection);
1338 if (drawn.teTop != null) {
1339 this.wrapper.style.top = drawn.teTop + "px";
1340 this.wrapper.style.left = drawn.teLeft + "px";
1341 }
1342 },
1343
1344 // Reset the input to correspond to the selection (or to be empty,
1345 // when not typing and nothing is selected)
1346 reset: function(typing) {
1347 if (this.contextMenuPending) return;
1348 var minimal, selected, cm = this.cm, doc = cm.doc;
1349 if (cm.somethingSelected()) {
1350 this.prevInput = "";
1351 var range = doc.sel.primary();
1352 minimal = hasCopyEvent &&
1353 (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
1354 var content = minimal ? "-" : selected || cm.getSelection();
1355 this.textarea.value = content;
1356 if (cm.state.focused) selectInput(this.textarea);
1357 if (ie && ie_version >= 9) this.hasSelection = content;
1358 } else if (!typing) {
1359 this.prevInput = this.textarea.value = "";
1360 if (ie && ie_version >= 9) this.hasSelection = null;
1361 }
1362 this.inaccurateSelection = minimal;
1363 },
1364
1365 getField: function() { return this.textarea; },
1366
1367 supportsTouch: function() { return false; },
1368
1369 focus: function() {
1370 if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
1371 try { this.textarea.focus(); }
1372 catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
1373 }
1374 },
1375
1376 blur: function() { this.textarea.blur(); },
1377
1378 resetPosition: function() {
1379 this.wrapper.style.top = this.wrapper.style.left = 0;
1380 },
1381
1382 receivedFocus: function() { this.slowPoll(); },
1383
1384 // Poll for input changes, using the normal rate of polling. This
1385 // runs as long as the editor is focused.
1386 slowPoll: function() {
1387 var input = this;
1388 if (input.pollingFast) return;
1389 input.polling.set(this.cm.options.pollInterval, function() {
1390 input.poll();
1391 if (input.cm.state.focused) input.slowPoll();
1392 });
1393 },
1394
1395 // When an event has just come in that is likely to add or change
1396 // something in the input textarea, we poll faster, to ensure that
1397 // the change appears on the screen quickly.
1398 fastPoll: function() {
1399 var missed = false, input = this;
1400 input.pollingFast = true;
1401 function p() {
1402 var changed = input.poll();
1403 if (!changed && !missed) {missed = true; input.polling.set(60, p);}
1404 else {input.pollingFast = false; input.slowPoll();}
1405 }
1406 input.polling.set(20, p);
1407 },
1408
1409 // Read input from the textarea, and update the document to match.
1410 // When something is selected, it is present in the textarea, and
1411 // selected (unless it is huge, in which case a placeholder is
1412 // used). When nothing is selected, the cursor sits after previously
1413 // seen text (can be empty), which is stored in prevInput (we must
1414 // not reset the textarea when typing, because that breaks IME).
1415 poll: function() {
1416 var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
1417 // Since this is called a *lot*, try to bail out as cheaply as
1418 // possible when it is clear that nothing happened. hasSelection
1419 // will be the case when there is a lot of text in the textarea,
1420 // in which case reading its value would be expensive.
1421 if (this.contextMenuPending || !cm.state.focused ||
1422 (hasSelection(input) && !prevInput && !this.composing) ||
1423 cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
1424 return false;
1425
1426 var text = input.value;
1427 // If nothing changed, bail.
1428 if (text == prevInput && !cm.somethingSelected()) return false;
1429 // Work around nonsensical selection resetting in IE9/10, and
1430 // inexplicable appearance of private area unicode characters on
1431 // some key combos in Mac (#2689).
1432 if (ie && ie_version >= 9 && this.hasSelection === text ||
1433 mac && /[\uf700-\uf7ff]/.test(text)) {
1434 cm.display.input.reset();
1435 return false;
1436 }
1437
1438 if (cm.doc.sel == cm.display.selForContextMenu) {
1439 var first = text.charCodeAt(0);
1440 if (first == 0x200b && !prevInput) prevInput = "\u200b";
1441 if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); }
1442 }
1443 // Find the part of the input that is actually new
1444 var same = 0, l = Math.min(prevInput.length, text.length);
1445 while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
1446
1447 var self = this;
1448 runInOp(cm, function() {
1449 applyTextInput(cm, text.slice(same), prevInput.length - same,
1450 null, self.composing ? "*compose" : null);
1451
1452 // Don't leave long text in the textarea, since it makes further polling slow
1453 if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "";
1454 else self.prevInput = text;
1455
1456 if (self.composing) {
1457 self.composing.range.clear();
1458 self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"),
1459 {className: "CodeMirror-composing"});
1460 }
1461 });
1462 return true;
1463 },
1464
1465 ensurePolled: function() {
1466 if (this.pollingFast && this.poll()) this.pollingFast = false;
1467 },
1468
1469 onKeyPress: function() {
1470 if (ie && ie_version >= 9) this.hasSelection = null;
1471 this.fastPoll();
1472 },
1473
1474 onContextMenu: function(e) {
1475 var input = this, cm = input.cm, display = cm.display, te = input.textarea;
1476 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
1477 if (!pos || presto) return; // Opera is difficult.
1478
1479 // Reset the current text selection only if the click is done outside of the selection
1480 // and 'resetSelectionOnContextMenu' option is true.
1481 var reset = cm.options.resetSelectionOnContextMenu;
1482 if (reset && cm.doc.sel.contains(pos) == -1)
1483 operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
1484
1485 var oldCSS = te.style.cssText;
1486 input.wrapper.style.position = "absolute";
1487 te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
1488 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
1489 (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
1490 "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
1491 if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
1492 display.input.focus();
1493 if (webkit) window.scrollTo(null, oldScrollY);
1494 display.input.reset();
1495 // Adds "Select all" to context menu in FF
1496 if (!cm.somethingSelected()) te.value = input.prevInput = " ";
1497 input.contextMenuPending = true;
1498 display.selForContextMenu = cm.doc.sel;
1499 clearTimeout(display.detectingSelectAll);
1500
1501 // Select-all will be greyed out if there's nothing to select, so
1502 // this adds a zero-width space so that we can later check whether
1503 // it got selected.
1504 function prepareSelectAllHack() {
1505 if (te.selectionStart != null) {
1506 var selected = cm.somethingSelected();
1507 var extval = "\u200b" + (selected ? te.value : "");
1508 te.value = "\u21da"; // Used to catch context-menu undo
1509 te.value = extval;
1510 input.prevInput = selected ? "" : "\u200b";
1511 te.selectionStart = 1; te.selectionEnd = extval.length;
1512 // Re-set this, in case some other handler touched the
1513 // selection in the meantime.
1514 display.selForContextMenu = cm.doc.sel;
1515 }
1516 }
1517 function rehide() {
1518 input.contextMenuPending = false;
1519 input.wrapper.style.position = "relative";
1520 te.style.cssText = oldCSS;
1521 if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
1522
1523 // Try to detect the user choosing select-all
1524 if (te.selectionStart != null) {
1525 if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
1526 var i = 0, poll = function() {
1527 if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
1528 te.selectionEnd > 0 && input.prevInput == "\u200b")
1529 operation(cm, commands.selectAll)(cm);
1530 else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
1531 else display.input.reset();
1532 };
1533 display.detectingSelectAll = setTimeout(poll, 200);
1534 }
1535 }
1536
1537 if (ie && ie_version >= 9) prepareSelectAllHack();
1538 if (captureRightClick) {
1539 e_stop(e);
1540 var mouseup = function() {
1541 off(window, "mouseup", mouseup);
1542 setTimeout(rehide, 20);
1543 };
1544 on(window, "mouseup", mouseup);
1545 } else {
1546 setTimeout(rehide, 50);
1547 }
1548 },
1549
1550 readOnlyChanged: function(val) {
1551 if (!val) this.reset();
1552 },
1553
1554 setUneditable: nothing,
1555
1556 needsContentAttribute: false
1557 }, TextareaInput.prototype);
1558
1559 // CONTENTEDITABLE INPUT STYLE
1560
1561 function ContentEditableInput(cm) {
1562 this.cm = cm;
1563 this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
1564 this.polling = new Delayed();
1565 this.gracePeriod = false;
1566 }
1567
1568 ContentEditableInput.prototype = copyObj({
1569 init: function(display) {
1570 var input = this, cm = input.cm;
1571 var div = input.div = display.lineDiv;
1572 disableBrowserMagic(div);
1573
1574 on(div, "paste", function(e) {
1575 if (!signalDOMEvent(cm, e)) handlePaste(e, cm);
1576 })
1577
1578 on(div, "compositionstart", function(e) {
1579 var data = e.data;
1580 input.composing = {sel: cm.doc.sel, data: data, startData: data};
1581 if (!data) return;
1582 var prim = cm.doc.sel.primary();
1583 var line = cm.getLine(prim.head.line);
1584 var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));
1585 if (found > -1 && found <= prim.head.ch)
1586 input.composing.sel = simpleSelection(Pos(prim.head.line, found),
1587 Pos(prim.head.line, found + data.length));
1588 });
1589 on(div, "compositionupdate", function(e) {
1590 input.composing.data = e.data;
1591 });
1592 on(div, "compositionend", function(e) {
1593 var ours = input.composing;
1594 if (!ours) return;
1595 if (e.data != ours.startData && !/\u200b/.test(e.data))
1596 ours.data = e.data;
1597 // Need a small delay to prevent other code (input event,
1598 // selection polling) from doing damage when fired right after
1599 // compositionend.
1600 setTimeout(function() {
1601 if (!ours.handled)
1602 input.applyComposition(ours);
1603 if (input.composing == ours)
1604 input.composing = null;
1605 }, 50);
1606 });
1607
1608 on(div, "touchstart", function() {
1609 input.forceCompositionEnd();
1610 });
1611
1612 on(div, "input", function() {
1613 if (input.composing) return;
1614 if (cm.isReadOnly() || !input.pollContent())
1615 runInOp(input.cm, function() {regChange(cm);});
1616 });
1617
1618 function onCopyCut(e) {
1619 if (signalDOMEvent(cm, e)) return
1620 if (cm.somethingSelected()) {
1621 lastCopied = cm.getSelections();
1622 if (e.type == "cut") cm.replaceSelection("", null, "cut");
1623 } else if (!cm.options.lineWiseCopyCut) {
1624 return;
1625 } else {
1626 var ranges = copyableRanges(cm);
1627 lastCopied = ranges.text;
1628 if (e.type == "cut") {
1629 cm.operation(function() {
1630 cm.setSelections(ranges.ranges, 0, sel_dontScroll);
1631 cm.replaceSelection("", null, "cut");
1632 });
1633 }
1634 }
1635 // iOS exposes the clipboard API, but seems to discard content inserted into it
1636 if (e.clipboardData && !ios) {
1637 e.preventDefault();
1638 e.clipboardData.clearData();
1639 e.clipboardData.setData("text/plain", lastCopied.join("\n"));
1640 } else {
1641 // Old-fashioned briefly-focus-a-textarea hack
1642 var kludge = hiddenTextarea(), te = kludge.firstChild;
1643 cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
1644 te.value = lastCopied.join("\n");
1645 var hadFocus = document.activeElement;
1646 selectInput(te);
1647 setTimeout(function() {
1648 cm.display.lineSpace.removeChild(kludge);
1649 hadFocus.focus();
1650 }, 50);
1651 }
1652 }
1653 on(div, "copy", onCopyCut);
1654 on(div, "cut", onCopyCut);
1655 },
1656
1657 prepareSelection: function() {
1658 var result = prepareSelection(this.cm, false);
1659 result.focus = this.cm.state.focused;
1660 return result;
1661 },
1662
1663 showSelection: function(info) {
1664 if (!info || !this.cm.display.view.length) return;
1665 if (info.focus) this.showPrimarySelection();
1666 this.showMultipleSelections(info);
1667 },
1668
1669 showPrimarySelection: function() {
1670 var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
1671 var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
1672 var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
1673 if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
1674 cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
1675 cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
1676 return;
1677
1678 var start = posToDOM(this.cm, prim.from());
1679 var end = posToDOM(this.cm, prim.to());
1680 if (!start && !end) return;
1681
1682 var view = this.cm.display.view;
1683 var old = sel.rangeCount && sel.getRangeAt(0);
1684 if (!start) {
1685 start = {node: view[0].measure.map[2], offset: 0};
1686 } else if (!end) { // FIXME dangerously hacky
1687 var measure = view[view.length - 1].measure;
1688 var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
1689 end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
1690 }
1691
1692 try { var rng = range(start.node, start.offset, end.offset, end.node); }
1693 catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
1694 if (rng) {
1695 if (!gecko && this.cm.state.focused) {
1696 sel.collapse(start.node, start.offset);
1697 if (!rng.collapsed) sel.addRange(rng);
1698 } else {
1699 sel.removeAllRanges();
1700 sel.addRange(rng);
1701 }
1702 if (old && sel.anchorNode == null) sel.addRange(old);
1703 else if (gecko) this.startGracePeriod();
1704 }
1705 this.rememberSelection();
1706 },
1707
1708 startGracePeriod: function() {
1709 var input = this;
1710 clearTimeout(this.gracePeriod);
1711 this.gracePeriod = setTimeout(function() {
1712 input.gracePeriod = false;
1713 if (input.selectionChanged())
1714 input.cm.operation(function() { input.cm.curOp.selectionChanged = true; });
1715 }, 20);
1716 },
1717
1718 showMultipleSelections: function(info) {
1719 removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
1720 removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
1721 },
1722
1723 rememberSelection: function() {
1724 var sel = window.getSelection();
1725 this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
1726 this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
1727 },
1728
1729 selectionInEditor: function() {
1730 var sel = window.getSelection();
1731 if (!sel.rangeCount) return false;
1732 var node = sel.getRangeAt(0).commonAncestorContainer;
1733 return contains(this.div, node);
1734 },
1735
1736 focus: function() {
1737 if (this.cm.options.readOnly != "nocursor") this.div.focus();
1738 },
1739 blur: function() { this.div.blur(); },
1740 getField: function() { return this.div; },
1741
1742 supportsTouch: function() { return true; },
1743
1744 receivedFocus: function() {
1745 var input = this;
1746 if (this.selectionInEditor())
1747 this.pollSelection();
1748 else
1749 runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });
1750
1751 function poll() {
1752 if (input.cm.state.focused) {
1753 input.pollSelection();
1754 input.polling.set(input.cm.options.pollInterval, poll);
1755 }
1756 }
1757 this.polling.set(this.cm.options.pollInterval, poll);
1758 },
1759
1760 selectionChanged: function() {
1761 var sel = window.getSelection();
1762 return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
1763 sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;
1764 },
1765
1766 pollSelection: function() {
1767 if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
1768 var sel = window.getSelection(), cm = this.cm;
1769 this.rememberSelection();
1770 var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
1771 var head = domToPos(cm, sel.focusNode, sel.focusOffset);
1772 if (anchor && head) runInOp(cm, function() {
1773 setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
1774 if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
1775 });
1776 }
1777 },
1778
1779 pollContent: function() {
1780 var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
1781 var from = sel.from(), to = sel.to();
1782 if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;
1783
1784 var fromIndex;
1785 if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
1786 var fromLine = lineNo(display.view[0].line);
1787 var fromNode = display.view[0].node;
1788 } else {
1789 var fromLine = lineNo(display.view[fromIndex].line);
1790 var fromNode = display.view[fromIndex - 1].node.nextSibling;
1791 }
1792 var toIndex = findViewIndex(cm, to.line);
1793 if (toIndex == display.view.length - 1) {
1794 var toLine = display.viewTo - 1;
1795 var toNode = display.lineDiv.lastChild;
1796 } else {
1797 var toLine = lineNo(display.view[toIndex + 1].line) - 1;
1798 var toNode = display.view[toIndex + 1].node.previousSibling;
1799 }
1800
1801 var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
1802 var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
1803 while (newText.length > 1 && oldText.length > 1) {
1804 if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
1805 else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
1806 else break;
1807 }
1808
1809 var cutFront = 0, cutEnd = 0;
1810 var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
1811 while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
1812 ++cutFront;
1813 var newBot = lst(newText), oldBot = lst(oldText);
1814 var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
1815 oldBot.length - (oldText.length == 1 ? cutFront : 0));
1816 while (cutEnd < maxCutEnd &&
1817 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
1818 ++cutEnd;
1819
1820 newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
1821 newText[0] = newText[0].slice(cutFront);
1822
1823 var chFrom = Pos(fromLine, cutFront);
1824 var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
1825 if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
1826 replaceRange(cm.doc, newText, chFrom, chTo, "+input");
1827 return true;
1828 }
1829 },
1830
1831 ensurePolled: function() {
1832 this.forceCompositionEnd();
1833 },
1834 reset: function() {
1835 this.forceCompositionEnd();
1836 },
1837 forceCompositionEnd: function() {
1838 if (!this.composing || this.composing.handled) return;
1839 this.applyComposition(this.composing);
1840 this.composing.handled = true;
1841 this.div.blur();
1842 this.div.focus();
1843 },
1844 applyComposition: function(composing) {
1845 if (this.cm.isReadOnly())
1846 operation(this.cm, regChange)(this.cm)
1847 else if (composing.data && composing.data != composing.startData)
1848 operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
1849 },
1850
1851 setUneditable: function(node) {
1852 node.contentEditable = "false"
1853 },
1854
1855 onKeyPress: function(e) {
1856 e.preventDefault();
1857 if (!this.cm.isReadOnly())
1858 operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
1859 },
1860
1861 readOnlyChanged: function(val) {
1862 this.div.contentEditable = String(val != "nocursor")
1863 },
1864
1865 onContextMenu: nothing,
1866 resetPosition: nothing,
1867
1868 needsContentAttribute: true
1869 }, ContentEditableInput.prototype);
1870
1871 function posToDOM(cm, pos) {
1872 var view = findViewForLine(cm, pos.line);
1873 if (!view || view.hidden) return null;
1874 var line = getLine(cm.doc, pos.line);
1875 var info = mapFromLineView(view, line, pos.line);
1876
1877 var order = getOrder(line), side = "left";
1878 if (order) {
1879 var partPos = getBidiPartAt(order, pos.ch);
1880 side = partPos % 2 ? "right" : "left";
1881 }
1882 var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
1883 result.offset = result.collapse == "right" ? result.end : result.start;
1884 return result;
1885 }
1886
1887 function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }
1888
1889 function domToPos(cm, node, offset) {
1890 var lineNode;
1891 if (node == cm.display.lineDiv) {
1892 lineNode = cm.display.lineDiv.childNodes[offset];
1893 if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);
1894 node = null; offset = 0;
1895 } else {
1896 for (lineNode = node;; lineNode = lineNode.parentNode) {
1897 if (!lineNode || lineNode == cm.display.lineDiv) return null;
1898 if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;
1899 }
1900 }
1901 for (var i = 0; i < cm.display.view.length; i++) {
1902 var lineView = cm.display.view[i];
1903 if (lineView.node == lineNode)
1904 return locateNodeInLineView(lineView, node, offset);
1905 }
1906 }
1907
1908 function locateNodeInLineView(lineView, node, offset) {
1909 var wrapper = lineView.text.firstChild, bad = false;
1910 if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);
1911 if (node == wrapper) {
1912 bad = true;
1913 node = wrapper.childNodes[offset];
1914 offset = 0;
1915 if (!node) {
1916 var line = lineView.rest ? lst(lineView.rest) : lineView.line;
1917 return badPos(Pos(lineNo(line), line.text.length), bad);
1918 }
1919 }
1920
1921 var textNode = node.nodeType == 3 ? node : null, topNode = node;
1922 if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
1923 textNode = node.firstChild;
1924 if (offset) offset = textNode.nodeValue.length;
1925 }
1926 while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
1927 var measure = lineView.measure, maps = measure.maps;
1928
1929 function find(textNode, topNode, offset) {
1930 for (var i = -1; i < (maps ? maps.length : 0); i++) {
1931 var map = i < 0 ? measure.map : maps[i];
1932 for (var j = 0; j < map.length; j += 3) {
1933 var curNode = map[j + 2];
1934 if (curNode == textNode || curNode == topNode) {
1935 var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
1936 var ch = map[j] + offset;
1937 if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];
1938 return Pos(line, ch);
1939 }
1940 }
1941 }
1942 }
1943 var found = find(textNode, topNode, offset);
1944 if (found) return badPos(found, bad);
1945
1946 // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
1947 for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
1948 found = find(after, after.firstChild, 0);
1949 if (found)
1950 return badPos(Pos(found.line, found.ch - dist), bad);
1951 else
1952 dist += after.textContent.length;
1953 }
1954 for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
1955 found = find(before, before.firstChild, -1);
1956 if (found)
1957 return badPos(Pos(found.line, found.ch + dist), bad);
1958 else
1959 dist += after.textContent.length;
1960 }
1961 }
1962
1963 function domTextBetween(cm, from, to, fromLine, toLine) {
1964 var text = "", closing = false, lineSep = cm.doc.lineSeparator();
1965 function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }
1966 function walk(node) {
1967 if (node.nodeType == 1) {
1968 var cmText = node.getAttribute("cm-text");
1969 if (cmText != null) {
1970 if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "");
1971 text += cmText;
1972 return;
1973 }
1974 var markerID = node.getAttribute("cm-marker"), range;
1975 if (markerID) {
1976 var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
1977 if (found.length && (range = found[0].find()))
1978 text += getBetween(cm.doc, range.from, range.to).join(lineSep);
1979 return;
1980 }
1981 if (node.getAttribute("contenteditable") == "false") return;
1982 for (var i = 0; i < node.childNodes.length; i++)
1983 walk(node.childNodes[i]);
1984 if (/^(pre|div|p)$/i.test(node.nodeName))
1985 closing = true;
1986 } else if (node.nodeType == 3) {
1987 var val = node.nodeValue;
1988 if (!val) return;
1989 if (closing) {
1990 text += lineSep;
1991 closing = false;
1992 }
1993 text += val;
1994 }
1995 }
1996 for (;;) {
1997 walk(from);
1998 if (from == to) break;
1999 from = from.nextSibling;
2000 }
2001 return text;
2002 }
2003
2004 CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
2005
2006 // SELECTION / CURSOR
2007
2008 // Selection objects are immutable. A new one is created every time
2009 // the selection changes. A selection is one or more non-overlapping
2010 // (and non-touching) ranges, sorted, and an integer that indicates
2011 // which one is the primary selection (the one that's scrolled into
2012 // view, that getCursor returns, etc).
2013 function Selection(ranges, primIndex) {
2014 this.ranges = ranges;
2015 this.primIndex = primIndex;
2016 }
2017
2018 Selection.prototype = {
2019 primary: function() { return this.ranges[this.primIndex]; },
2020 equals: function(other) {
2021 if (other == this) return true;
2022 if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
2023 for (var i = 0; i < this.ranges.length; i++) {
2024 var here = this.ranges[i], there = other.ranges[i];
2025 if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
2026 }
2027 return true;
2028 },
2029 deepCopy: function() {
2030 for (var out = [], i = 0; i < this.ranges.length; i++)
2031 out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
2032 return new Selection(out, this.primIndex);
2033 },
2034 somethingSelected: function() {
2035 for (var i = 0; i < this.ranges.length; i++)
2036 if (!this.ranges[i].empty()) return true;
2037 return false;
2038 },
2039 contains: function(pos, end) {
2040 if (!end) end = pos;
2041 for (var i = 0; i < this.ranges.length; i++) {
2042 var range = this.ranges[i];
2043 if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
2044 return i;
2045 }
2046 return -1;
2047 }
2048 };
2049
2050 function Range(anchor, head) {
2051 this.anchor = anchor; this.head = head;
2052 }
2053
2054 Range.prototype = {
2055 from: function() { return minPos(this.anchor, this.head); },
2056 to: function() { return maxPos(this.anchor, this.head); },
2057 empty: function() {
2058 return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
2059 }
2060 };
2061
2062 // Take an unsorted, potentially overlapping set of ranges, and
2063 // build a selection out of it. 'Consumes' ranges array (modifying
2064 // it).
2065 function normalizeSelection(ranges, primIndex) {
2066 var prim = ranges[primIndex];
2067 ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
2068 primIndex = indexOf(ranges, prim);
2069 for (var i = 1; i < ranges.length; i++) {
2070 var cur = ranges[i], prev = ranges[i - 1];
2071 if (cmp(prev.to(), cur.from()) >= 0) {
2072 var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
2073 var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
2074 if (i <= primIndex) --primIndex;
2075 ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
2076 }
2077 }
2078 return new Selection(ranges, primIndex);
2079 }
2080
2081 function simpleSelection(anchor, head) {
2082 return new Selection([new Range(anchor, head || anchor)], 0);
2083 }
2084
2085 // Most of the external API clips given positions to make sure they
2086 // actually exist within the document.
2087 function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
2088 function clipPos(doc, pos) {
2089 if (pos.line < doc.first) return Pos(doc.first, 0);
2090 var last = doc.first + doc.size - 1;
2091 if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
2092 return clipToLen(pos, getLine(doc, pos.line).text.length);
2093 }
2094 function clipToLen(pos, linelen) {
2095 var ch = pos.ch;
2096 if (ch == null || ch > linelen) return Pos(pos.line, linelen);
2097 else if (ch < 0) return Pos(pos.line, 0);
2098 else return pos;
2099 }
2100 function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
2101 function clipPosArray(doc, array) {
2102 for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
2103 return out;
2104 }
2105
2106 // SELECTION UPDATES
2107
2108 // The 'scroll' parameter given to many of these indicated whether
2109 // the new cursor position should be scrolled into view after
2110 // modifying the selection.
2111
2112 // If shift is held or the extend flag is set, extends a range to
2113 // include a given position (and optionally a second position).
2114 // Otherwise, simply returns the range between the given positions.
2115 // Used for cursor motion and such.
2116 function extendRange(doc, range, head, other) {
2117 if (doc.cm && doc.cm.display.shift || doc.extend) {
2118 var anchor = range.anchor;
2119 if (other) {
2120 var posBefore = cmp(head, anchor) < 0;
2121 if (posBefore != (cmp(other, anchor) < 0)) {
2122 anchor = head;
2123 head = other;
2124 } else if (posBefore != (cmp(head, other) < 0)) {
2125 head = other;
2126 }
2127 }
2128 return new Range(anchor, head);
2129 } else {
2130 return new Range(other || head, head);
2131 }
2132 }
2133
2134 // Extend the primary selection range, discard the rest.
2135 function extendSelection(doc, head, other, options) {
2136 setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
2137 }
2138
2139 // Extend all selections (pos is an array of selections with length
2140 // equal the number of selections)
2141 function extendSelections(doc, heads, options) {
2142 for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
2143 out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
2144 var newSel = normalizeSelection(out, doc.sel.primIndex);
2145 setSelection(doc, newSel, options);
2146 }
2147
2148 // Updates a single range in the selection.
2149 function replaceOneSelection(doc, i, range, options) {
2150 var ranges = doc.sel.ranges.slice(0);
2151 ranges[i] = range;
2152 setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
2153 }
2154
2155 // Reset the selection to a single range.
2156 function setSimpleSelection(doc, anchor, head, options) {
2157 setSelection(doc, simpleSelection(anchor, head), options);
2158 }
2159
2160 // Give beforeSelectionChange handlers a change to influence a
2161 // selection update.
2162 function filterSelectionChange(doc, sel, options) {
2163 var obj = {
2164 ranges: sel.ranges,
2165 update: function(ranges) {
2166 this.ranges = [];
2167 for (var i = 0; i < ranges.length; i++)
2168 this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
2169 clipPos(doc, ranges[i].head));
2170 },
2171 origin: options && options.origin
2172 };
2173 signal(doc, "beforeSelectionChange", doc, obj);
2174 if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
2175 if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
2176 else return sel;
2177 }
2178
2179 function setSelectionReplaceHistory(doc, sel, options) {
2180 var done = doc.history.done, last = lst(done);
2181 if (last && last.ranges) {
2182 done[done.length - 1] = sel;
2183 setSelectionNoUndo(doc, sel, options);
2184 } else {
2185 setSelection(doc, sel, options);
2186 }
2187 }
2188
2189 // Set a new selection.
2190 function setSelection(doc, sel, options) {
2191 setSelectionNoUndo(doc, sel, options);
2192 addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
2193 }
2194
2195 function setSelectionNoUndo(doc, sel, options) {
2196 if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
2197 sel = filterSelectionChange(doc, sel, options);
2198
2199 var bias = options && options.bias ||
2200 (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
2201 setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
2202
2203 if (!(options && options.scroll === false) && doc.cm)
2204 ensureCursorVisible(doc.cm);
2205 }
2206
2207 function setSelectionInner(doc, sel) {
2208 if (sel.equals(doc.sel)) return;
2209
2210 doc.sel = sel;
2211
2212 if (doc.cm) {
2213 doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
2214 signalCursorActivity(doc.cm);
2215 }
2216 signalLater(doc, "cursorActivity", doc);
2217 }
2218
2219 // Verify that the selection does not partially select any atomic
2220 // marked ranges.
2221 function reCheckSelection(doc) {
2222 setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
2223 }
2224
2225 // Return a selection that does not partially select any atomic
2226 // ranges.
2227 function skipAtomicInSelection(doc, sel, bias, mayClear) {
2228 var out;
2229 for (var i = 0; i < sel.ranges.length; i++) {
2230 var range = sel.ranges[i];
2231 var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
2232 var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
2233 var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
2234 if (out || newAnchor != range.anchor || newHead != range.head) {
2235 if (!out) out = sel.ranges.slice(0, i);
2236 out[i] = new Range(newAnchor, newHead);
2237 }
2238 }
2239 return out ? normalizeSelection(out, sel.primIndex) : sel;
2240 }
2241
2242 function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
2243 var line = getLine(doc, pos.line);
2244 if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
2245 var sp = line.markedSpans[i], m = sp.marker;
2246 if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
2247 (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
2248 if (mayClear) {
2249 signal(m, "beforeCursorEnter");
2250 if (m.explicitlyCleared) {
2251 if (!line.markedSpans) break;
2252 else {--i; continue;}
2253 }
2254 }
2255 if (!m.atomic) continue;
2256
2257 if (oldPos) {
2258 var near = m.find(dir < 0 ? 1 : -1), diff;
2259 if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, line);
2260 if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
2261 return skipAtomicInner(doc, near, pos, dir, mayClear);
2262 }
2263
2264 var far = m.find(dir < 0 ? -1 : 1);
2265 if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) far = movePos(doc, far, dir, line);
2266 return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;
2267 }
2268 }
2269 return pos;
2270 }
2271
2272 // Ensure a given position is not inside an atomic range.
2273 function skipAtomic(doc, pos, oldPos, bias, mayClear) {
2274 var dir = bias || 1;
2275 var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
2276 (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
2277 skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
2278 (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
2279 if (!found) {
2280 doc.cantEdit = true;
2281 return Pos(doc.first, 0);
2282 }
2283 return found;
2284 }
2285
2286 function movePos(doc, pos, dir, line) {
2287 if (dir < 0 && pos.ch == 0) {
2288 if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1));
2289 else return null;
2290 } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
2291 if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0);
2292 else return null;
2293 } else {
2294 return new Pos(pos.line, pos.ch + dir);
2295 }
2296 }
2297
2298 // SELECTION DRAWING
2299
2300 function updateSelection(cm) {
2301 cm.display.input.showSelection(cm.display.input.prepareSelection());
2302 }
2303
2304 function prepareSelection(cm, primary) {
2305 var doc = cm.doc, result = {};
2306 var curFragment = result.cursors = document.createDocumentFragment();
2307 var selFragment = result.selection = document.createDocumentFragment();
2308
2309 for (var i = 0; i < doc.sel.ranges.length; i++) {
2310 if (primary === false && i == doc.sel.primIndex) continue;
2311 var range = doc.sel.ranges[i];
2312 var collapsed = range.empty();
2313 if (collapsed || cm.options.showCursorWhenSelecting)
2314 drawSelectionCursor(cm, range.head, curFragment);
2315 if (!collapsed)
2316 drawSelectionRange(cm, range, selFragment);
2317 }
2318 return result;
2319 }
2320
2321 // Draws a cursor for the given range
2322 function drawSelectionCursor(cm, head, output) {
2323 var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
2324
2325 var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
2326 cursor.style.left = pos.left + "px";
2327 cursor.style.top = pos.top + "px";
2328 cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
2329
2330 if (pos.other) {
2331 // Secondary cursor, shown when on a 'jump' in bi-directional text
2332 var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
2333 otherCursor.style.display = "";
2334 otherCursor.style.left = pos.other.left + "px";
2335 otherCursor.style.top = pos.other.top + "px";
2336 otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
2337 }
2338 }
2339
2340 // Draws the given range as a highlighted selection
2341 function drawSelectionRange(cm, range, output) {
2342 var display = cm.display, doc = cm.doc;
2343 var fragment = document.createDocumentFragment();
2344 var padding = paddingH(cm.display), leftSide = padding.left;
2345 var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
2346
2347 function add(left, top, width, bottom) {
2348 if (top < 0) top = 0;
2349 top = Math.round(top);
2350 bottom = Math.round(bottom);
2351 fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
2352 "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
2353 "px; height: " + (bottom - top) + "px"));
2354 }
2355
2356 function drawForLine(line, fromArg, toArg) {
2357 var lineObj = getLine(doc, line);
2358 var lineLen = lineObj.text.length;
2359 var start, end;
2360 function coords(ch, bias) {
2361 return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
2362 }
2363
2364 iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
2365 var leftPos = coords(from, "left"), rightPos, left, right;
2366 if (from == to) {
2367 rightPos = leftPos;
2368 left = right = leftPos.left;
2369 } else {
2370 rightPos = coords(to - 1, "right");
2371 if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
2372 left = leftPos.left;
2373 right = rightPos.right;
2374 }
2375 if (fromArg == null && from == 0) left = leftSide;
2376 if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
2377 add(left, leftPos.top, null, leftPos.bottom);
2378 left = leftSide;
2379 if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
2380 }
2381 if (toArg == null && to == lineLen) right = rightSide;
2382 if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
2383 start = leftPos;
2384 if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
2385 end = rightPos;
2386 if (left < leftSide + 1) left = leftSide;
2387 add(left, rightPos.top, right - left, rightPos.bottom);
2388 });
2389 return {start: start, end: end};
2390 }
2391
2392 var sFrom = range.from(), sTo = range.to();
2393 if (sFrom.line == sTo.line) {
2394 drawForLine(sFrom.line, sFrom.ch, sTo.ch);
2395 } else {
2396 var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
2397 var singleVLine = visualLine(fromLine) == visualLine(toLine);
2398 var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
2399 var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
2400 if (singleVLine) {
2401 if (leftEnd.top < rightStart.top - 2) {
2402 add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
2403 add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
2404 } else {
2405 add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
2406 }
2407 }
2408 if (leftEnd.bottom < rightStart.top)
2409 add(leftSide, leftEnd.bottom, null, rightStart.top);
2410 }
2411
2412 output.appendChild(fragment);
2413 }
2414
2415 // Cursor-blinking
2416 function restartBlink(cm) {
2417 if (!cm.state.focused) return;
2418 var display = cm.display;
2419 clearInterval(display.blinker);
2420 var on = true;
2421 display.cursorDiv.style.visibility = "";
2422 if (cm.options.cursorBlinkRate > 0)
2423 display.blinker = setInterval(function() {
2424 display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
2425 }, cm.options.cursorBlinkRate);
2426 else if (cm.options.cursorBlinkRate < 0)
2427 display.cursorDiv.style.visibility = "hidden";
2428 }
2429
2430 // HIGHLIGHT WORKER
2431
2432 function startWorker(cm, time) {
2433 if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
2434 cm.state.highlight.set(time, bind(highlightWorker, cm));
2435 }
2436
2437 function highlightWorker(cm) {
2438 var doc = cm.doc;
2439 if (doc.frontier < doc.first) doc.frontier = doc.first;
2440 if (doc.frontier >= cm.display.viewTo) return;
2441 var end = +new Date + cm.options.workTime;
2442 var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
2443 var changedLines = [];
2444
2445 doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
2446 if (doc.frontier >= cm.display.viewFrom) { // Visible
2447 var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength;
2448 var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true);
2449 line.styles = highlighted.styles;
2450 var oldCls = line.styleClasses, newCls = highlighted.classes;
2451 if (newCls) line.styleClasses = newCls;
2452 else if (oldCls) line.styleClasses = null;
2453 var ischange = !oldStyles || oldStyles.length != line.styles.length ||
2454 oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
2455 for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
2456 if (ischange) changedLines.push(doc.frontier);
2457 line.stateAfter = tooLong ? state : copyState(doc.mode, state);
2458 } else {
2459 if (line.text.length <= cm.options.maxHighlightLength)
2460 processLine(cm, line.text, state);
2461 line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
2462 }
2463 ++doc.frontier;
2464 if (+new Date > end) {
2465 startWorker(cm, cm.options.workDelay);
2466 return true;
2467 }
2468 });
2469 if (changedLines.length) runInOp(cm, function() {
2470 for (var i = 0; i < changedLines.length; i++)
2471 regLineChange(cm, changedLines[i], "text");
2472 });
2473 }
2474
2475 // Finds the line to start with when starting a parse. Tries to
2476 // find a line with a stateAfter, so that it can start with a
2477 // valid state. If that fails, it returns the line with the
2478 // smallest indentation, which tends to need the least context to
2479 // parse correctly.
2480 function findStartLine(cm, n, precise) {
2481 var minindent, minline, doc = cm.doc;
2482 var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
2483 for (var search = n; search > lim; --search) {
2484 if (search <= doc.first) return doc.first;
2485 var line = getLine(doc, search - 1);
2486 if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
2487 var indented = countColumn(line.text, null, cm.options.tabSize);
2488 if (minline == null || minindent > indented) {
2489 minline = search - 1;
2490 minindent = indented;
2491 }
2492 }
2493 return minline;
2494 }
2495
2496 function getStateBefore(cm, n, precise) {
2497 var doc = cm.doc, display = cm.display;
2498 if (!doc.mode.startState) return true;
2499 var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
2500 if (!state) state = startState(doc.mode);
2501 else state = copyState(doc.mode, state);
2502 doc.iter(pos, n, function(line) {
2503 processLine(cm, line.text, state);
2504 var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
2505 line.stateAfter = save ? copyState(doc.mode, state) : null;
2506 ++pos;
2507 });
2508 if (precise) doc.frontier = pos;
2509 return state;
2510 }
2511
2512 // POSITION MEASUREMENT
2513
2514 function paddingTop(display) {return display.lineSpace.offsetTop;}
2515 function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
2516 function paddingH(display) {
2517 if (display.cachedPaddingH) return display.cachedPaddingH;
2518 var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
2519 var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
2520 var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
2521 if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
2522 return data;
2523 }
2524
2525 function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
2526 function displayWidth(cm) {
2527 return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
2528 }
2529 function displayHeight(cm) {
2530 return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
2531 }
2532
2533 // Ensure the lineView.wrapping.heights array is populated. This is
2534 // an array of bottom offsets for the lines that make up a drawn
2535 // line. When lineWrapping is on, there might be more than one
2536 // height.
2537 function ensureLineHeights(cm, lineView, rect) {
2538 var wrapping = cm.options.lineWrapping;
2539 var curWidth = wrapping && displayWidth(cm);
2540 if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
2541 var heights = lineView.measure.heights = [];
2542 if (wrapping) {
2543 lineView.measure.width = curWidth;
2544 var rects = lineView.text.firstChild.getClientRects();
2545 for (var i = 0; i < rects.length - 1; i++) {
2546 var cur = rects[i], next = rects[i + 1];
2547 if (Math.abs(cur.bottom - next.bottom) > 2)
2548 heights.push((cur.bottom + next.top) / 2 - rect.top);
2549 }
2550 }
2551 heights.push(rect.bottom - rect.top);
2552 }
2553 }
2554
2555 // Find a line map (mapping character offsets to text nodes) and a
2556 // measurement cache for the given line number. (A line view might
2557 // contain multiple lines when collapsed ranges are present.)
2558 function mapFromLineView(lineView, line, lineN) {
2559 if (lineView.line == line)
2560 return {map: lineView.measure.map, cache: lineView.measure.cache};
2561 for (var i = 0; i < lineView.rest.length; i++)
2562 if (lineView.rest[i] == line)
2563 return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
2564 for (var i = 0; i < lineView.rest.length; i++)
2565 if (lineNo(lineView.rest[i]) > lineN)
2566 return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
2567 }
2568
2569 // Render a line into the hidden node display.externalMeasured. Used
2570 // when measurement is needed for a line that's not in the viewport.
2571 function updateExternalMeasurement(cm, line) {
2572 line = visualLine(line);
2573 var lineN = lineNo(line);
2574 var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
2575 view.lineN = lineN;
2576 var built = view.built = buildLineContent(cm, view);
2577 view.text = built.pre;
2578 removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
2579 return view;
2580 }
2581
2582 // Get a {top, bottom, left, right} box (in line-local coordinates)
2583 // for a given character.
2584 function measureChar(cm, line, ch, bias) {
2585 return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
2586 }
2587
2588 // Find a line view that corresponds to the given line number.
2589 function findViewForLine(cm, lineN) {
2590 if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
2591 return cm.display.view[findViewIndex(cm, lineN)];
2592 var ext = cm.display.externalMeasured;
2593 if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
2594 return ext;
2595 }
2596
2597 // Measurement can be split in two steps, the set-up work that
2598 // applies to the whole line, and the measurement of the actual
2599 // character. Functions like coordsChar, that need to do a lot of
2600 // measurements in a row, can thus ensure that the set-up work is
2601 // only done once.
2602 function prepareMeasureForLine(cm, line) {
2603 var lineN = lineNo(line);
2604 var view = findViewForLine(cm, lineN);
2605 if (view && !view.text) {
2606 view = null;
2607 } else if (view && view.changes) {
2608 updateLineForChanges(cm, view, lineN, getDimensions(cm));
2609 cm.curOp.forceUpdate = true;
2610 }
2611 if (!view)
2612 view = updateExternalMeasurement(cm, line);
2613
2614 var info = mapFromLineView(view, line, lineN);
2615 return {
2616 line: line, view: view, rect: null,
2617 map: info.map, cache: info.cache, before: info.before,
2618 hasHeights: false
2619 };
2620 }
2621
2622 // Given a prepared measurement object, measures the position of an
2623 // actual character (or fetches it from the cache).
2624 function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
2625 if (prepared.before) ch = -1;
2626 var key = ch + (bias || ""), found;
2627 if (prepared.cache.hasOwnProperty(key)) {
2628 found = prepared.cache[key];
2629 } else {
2630 if (!prepared.rect)
2631 prepared.rect = prepared.view.text.getBoundingClientRect();
2632 if (!prepared.hasHeights) {
2633 ensureLineHeights(cm, prepared.view, prepared.rect);
2634 prepared.hasHeights = true;
2635 }
2636 found = measureCharInner(cm, prepared, ch, bias);
2637 if (!found.bogus) prepared.cache[key] = found;
2638 }
2639 return {left: found.left, right: found.right,
2640 top: varHeight ? found.rtop : found.top,
2641 bottom: varHeight ? found.rbottom : found.bottom};
2642 }
2643
2644 var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
2645
2646 function nodeAndOffsetInLineMap(map, ch, bias) {
2647 var node, start, end, collapse;
2648 // First, search the line map for the text node corresponding to,
2649 // or closest to, the target character.
2650 for (var i = 0; i < map.length; i += 3) {
2651 var mStart = map[i], mEnd = map[i + 1];
2652 if (ch < mStart) {
2653 start = 0; end = 1;
2654 collapse = "left";
2655 } else if (ch < mEnd) {
2656 start = ch - mStart;
2657 end = start + 1;
2658 } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
2659 end = mEnd - mStart;
2660 start = end - 1;
2661 if (ch >= mEnd) collapse = "right";
2662 }
2663 if (start != null) {
2664 node = map[i + 2];
2665 if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
2666 collapse = bias;
2667 if (bias == "left" && start == 0)
2668 while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
2669 node = map[(i -= 3) + 2];
2670 collapse = "left";
2671 }
2672 if (bias == "right" && start == mEnd - mStart)
2673 while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
2674 node = map[(i += 3) + 2];
2675 collapse = "right";
2676 }
2677 break;
2678 }
2679 }
2680 return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};
2681 }
2682
2683 function measureCharInner(cm, prepared, ch, bias) {
2684 var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
2685 var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
2686
2687 var rect;
2688 if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
2689 for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
2690 while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;
2691 while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;
2692 if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) {
2693 rect = node.parentNode.getBoundingClientRect();
2694 } else if (ie && cm.options.lineWrapping) {
2695 var rects = range(node, start, end).getClientRects();
2696 if (rects.length)
2697 rect = rects[bias == "right" ? rects.length - 1 : 0];
2698 else
2699 rect = nullRect;
2700 } else {
2701 rect = range(node, start, end).getBoundingClientRect() || nullRect;
2702 }
2703 if (rect.left || rect.right || start == 0) break;
2704 end = start;
2705 start = start - 1;
2706 collapse = "right";
2707 }
2708 if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
2709 } else { // If it is a widget, simply get the box for the whole widget.
2710 if (start > 0) collapse = bias = "right";
2711 var rects;
2712 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
2713 rect = rects[bias == "right" ? rects.length - 1 : 0];
2714 else
2715 rect = node.getBoundingClientRect();
2716 }
2717 if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
2718 var rSpan = node.parentNode.getClientRects()[0];
2719 if (rSpan)
2720 rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
2721 else
2722 rect = nullRect;
2723 }
2724
2725 var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
2726 var mid = (rtop + rbot) / 2;
2727 var heights = prepared.view.measure.heights;
2728 for (var i = 0; i < heights.length - 1; i++)
2729 if (mid < heights[i]) break;
2730 var top = i ? heights[i - 1] : 0, bot = heights[i];
2731 var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
2732 right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
2733 top: top, bottom: bot};
2734 if (!rect.left && !rect.right) result.bogus = true;
2735 if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
2736
2737 return result;
2738 }
2739
2740 // Work around problem with bounding client rects on ranges being
2741 // returned incorrectly when zoomed on IE10 and below.
2742 function maybeUpdateRectForZooming(measure, rect) {
2743 if (!window.screen || screen.logicalXDPI == null ||
2744 screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
2745 return rect;
2746 var scaleX = screen.logicalXDPI / screen.deviceXDPI;
2747 var scaleY = screen.logicalYDPI / screen.deviceYDPI;
2748 return {left: rect.left * scaleX, right: rect.right * scaleX,
2749 top: rect.top * scaleY, bottom: rect.bottom * scaleY};
2750 }
2751
2752 function clearLineMeasurementCacheFor(lineView) {
2753 if (lineView.measure) {
2754 lineView.measure.cache = {};
2755 lineView.measure.heights = null;
2756 if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
2757 lineView.measure.caches[i] = {};
2758 }
2759 }
2760
2761 function clearLineMeasurementCache(cm) {
2762 cm.display.externalMeasure = null;
2763 removeChildren(cm.display.lineMeasure);
2764 for (var i = 0; i < cm.display.view.length; i++)
2765 clearLineMeasurementCacheFor(cm.display.view[i]);
2766 }
2767
2768 function clearCaches(cm) {
2769 clearLineMeasurementCache(cm);
2770 cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
2771 if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
2772 cm.display.lineNumChars = null;
2773 }
2774
2775 function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
2776 function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
2777
2778 // Converts a {top, bottom, left, right} box from line-local
2779 // coordinates into another coordinate system. Context may be one of
2780 // "line", "div" (display.lineDiv), "local"/null (editor), "window",
2781 // or "page".
2782 function intoCoordSystem(cm, lineObj, rect, context) {
2783 if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
2784 var size = widgetHeight(lineObj.widgets[i]);
2785 rect.top += size; rect.bottom += size;
2786 }
2787 if (context == "line") return rect;
2788 if (!context) context = "local";
2789 var yOff = heightAtLine(lineObj);
2790 if (context == "local") yOff += paddingTop(cm.display);
2791 else yOff -= cm.display.viewOffset;
2792 if (context == "page" || context == "window") {
2793 var lOff = cm.display.lineSpace.getBoundingClientRect();
2794 yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
2795 var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
2796 rect.left += xOff; rect.right += xOff;
2797 }
2798 rect.top += yOff; rect.bottom += yOff;
2799 return rect;
2800 }
2801
2802 // Coverts a box from "div" coords to another coordinate system.
2803 // Context may be "window", "page", "div", or "local"/null.
2804 function fromCoordSystem(cm, coords, context) {
2805 if (context == "div") return coords;
2806 var left = coords.left, top = coords.top;
2807 // First move into "page" coordinate system
2808 if (context == "page") {
2809 left -= pageScrollX();
2810 top -= pageScrollY();
2811 } else if (context == "local" || !context) {
2812 var localBox = cm.display.sizer.getBoundingClientRect();
2813 left += localBox.left;
2814 top += localBox.top;
2815 }
2816
2817 var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
2818 return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
2819 }
2820
2821 function charCoords(cm, pos, context, lineObj, bias) {
2822 if (!lineObj) lineObj = getLine(cm.doc, pos.line);
2823 return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
2824 }
2825
2826 // Returns a box for a given cursor position, which may have an
2827 // 'other' property containing the position of the secondary cursor
2828 // on a bidi boundary.
2829 function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
2830 lineObj = lineObj || getLine(cm.doc, pos.line);
2831 if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
2832 function get(ch, right) {
2833 var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
2834 if (right) m.left = m.right; else m.right = m.left;
2835 return intoCoordSystem(cm, lineObj, m, context);
2836 }
2837 function getBidi(ch, partPos) {
2838 var part = order[partPos], right = part.level % 2;
2839 if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
2840 part = order[--partPos];
2841 ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
2842 right = true;
2843 } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
2844 part = order[++partPos];
2845 ch = bidiLeft(part) - part.level % 2;
2846 right = false;
2847 }
2848 if (right && ch == part.to && ch > part.from) return get(ch - 1);
2849 return get(ch, right);
2850 }
2851 var order = getOrder(lineObj), ch = pos.ch;
2852 if (!order) return get(ch);
2853 var partPos = getBidiPartAt(order, ch);
2854 var val = getBidi(ch, partPos);
2855 if (bidiOther != null) val.other = getBidi(ch, bidiOther);
2856 return val;
2857 }
2858
2859 // Used to cheaply estimate the coordinates for a position. Used for
2860 // intermediate scroll updates.
2861 function estimateCoords(cm, pos) {
2862 var left = 0, pos = clipPos(cm.doc, pos);
2863 if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
2864 var lineObj = getLine(cm.doc, pos.line);
2865 var top = heightAtLine(lineObj) + paddingTop(cm.display);
2866 return {left: left, right: left, top: top, bottom: top + lineObj.height};
2867 }
2868
2869 // Positions returned by coordsChar contain some extra information.
2870 // xRel is the relative x position of the input coordinates compared
2871 // to the found position (so xRel > 0 means the coordinates are to
2872 // the right of the character position, for example). When outside
2873 // is true, that means the coordinates lie outside the line's
2874 // vertical range.
2875 function PosWithInfo(line, ch, outside, xRel) {
2876 var pos = Pos(line, ch);
2877 pos.xRel = xRel;
2878 if (outside) pos.outside = true;
2879 return pos;
2880 }
2881
2882 // Compute the character position closest to the given coordinates.
2883 // Input must be lineSpace-local ("div" coordinate system).
2884 function coordsChar(cm, x, y) {
2885 var doc = cm.doc;
2886 y += cm.display.viewOffset;
2887 if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
2888 var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
2889 if (lineN > last)
2890 return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
2891 if (x < 0) x = 0;
2892
2893 var lineObj = getLine(doc, lineN);
2894 for (;;) {
2895 var found = coordsCharInner(cm, lineObj, lineN, x, y);
2896 var merged = collapsedSpanAtEnd(lineObj);
2897 var mergedPos = merged && merged.find(0, true);
2898 if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
2899 lineN = lineNo(lineObj = mergedPos.to.line);
2900 else
2901 return found;
2902 }
2903 }
2904
2905 function coordsCharInner(cm, lineObj, lineNo, x, y) {
2906 var innerOff = y - heightAtLine(lineObj);
2907 var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
2908 var preparedMeasure = prepareMeasureForLine(cm, lineObj);
2909
2910 function getX(ch) {
2911 var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
2912 wrongLine = true;
2913 if (innerOff > sp.bottom) return sp.left - adjust;
2914 else if (innerOff < sp.top) return sp.left + adjust;
2915 else wrongLine = false;
2916 return sp.left;
2917 }
2918
2919 var bidi = getOrder(lineObj), dist = lineObj.text.length;
2920 var from = lineLeft(lineObj), to = lineRight(lineObj);
2921 var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
2922
2923 if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
2924 // Do a binary search between these bounds.
2925 for (;;) {
2926 if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
2927 var ch = x < fromX || x - fromX <= toX - x ? from : to;
2928 var xDiff = x - (ch == from ? fromX : toX);
2929 while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
2930 var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
2931 xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
2932 return pos;
2933 }
2934 var step = Math.ceil(dist / 2), middle = from + step;
2935 if (bidi) {
2936 middle = from;
2937 for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
2938 }
2939 var middleX = getX(middle);
2940 if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
2941 else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
2942 }
2943 }
2944
2945 var measureText;
2946 // Compute the default text height.
2947 function textHeight(display) {
2948 if (display.cachedTextHeight != null) return display.cachedTextHeight;
2949 if (measureText == null) {
2950 measureText = elt("pre");
2951 // Measure a bunch of lines, for browsers that compute
2952 // fractional heights.
2953 for (var i = 0; i < 49; ++i) {
2954 measureText.appendChild(document.createTextNode("x"));
2955 measureText.appendChild(elt("br"));
2956 }
2957 measureText.appendChild(document.createTextNode("x"));
2958 }
2959 removeChildrenAndAdd(display.measure, measureText);
2960 var height = measureText.offsetHeight / 50;
2961 if (height > 3) display.cachedTextHeight = height;
2962 removeChildren(display.measure);
2963 return height || 1;
2964 }
2965
2966 // Compute the default character width.
2967 function charWidth(display) {
2968 if (display.cachedCharWidth != null) return display.cachedCharWidth;
2969 var anchor = elt("span", "xxxxxxxxxx");
2970 var pre = elt("pre", [anchor]);
2971 removeChildrenAndAdd(display.measure, pre);
2972 var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
2973 if (width > 2) display.cachedCharWidth = width;
2974 return width || 10;
2975 }
2976
2977 // OPERATIONS
2978
2979 // Operations are used to wrap a series of changes to the editor
2980 // state in such a way that each change won't have to update the
2981 // cursor and display (which would be awkward, slow, and
2982 // error-prone). Instead, display updates are batched and then all
2983 // combined and executed at once.
2984
2985 var operationGroup = null;
2986
2987 var nextOpId = 0;
2988 // Start a new operation.
2989 function startOperation(cm) {
2990 cm.curOp = {
2991 cm: cm,
2992 viewChanged: false, // Flag that indicates that lines might need to be redrawn
2993 startHeight: cm.doc.height, // Used to detect need to update scrollbar
2994 forceUpdate: false, // Used to force a redraw
2995 updateInput: null, // Whether to reset the input textarea
2996 typing: false, // Whether this reset should be careful to leave existing text (for compositing)
2997 changeObjs: null, // Accumulated changes, for firing change events
2998 cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
2999 cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
3000 selectionChanged: false, // Whether the selection needs to be redrawn
3001 updateMaxLine: false, // Set when the widest line needs to be determined anew
3002 scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
3003 scrollToPos: null, // Used to scroll to a specific position
3004 focus: false,
3005 id: ++nextOpId // Unique ID
3006 };
3007 if (operationGroup) {
3008 operationGroup.ops.push(cm.curOp);
3009 } else {
3010 cm.curOp.ownsGroup = operationGroup = {
3011 ops: [cm.curOp],
3012 delayedCallbacks: []
3013 };
3014 }
3015 }
3016
3017 function fireCallbacksForOps(group) {
3018 // Calls delayed callbacks and cursorActivity handlers until no
3019 // new ones appear
3020 var callbacks = group.delayedCallbacks, i = 0;
3021 do {
3022 for (; i < callbacks.length; i++)
3023 callbacks[i].call(null);
3024 for (var j = 0; j < group.ops.length; j++) {
3025 var op = group.ops[j];
3026 if (op.cursorActivityHandlers)
3027 while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
3028 op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm);
3029 }
3030 } while (i < callbacks.length);
3031 }
3032
3033 // Finish an operation, updating the display and signalling delayed events
3034 function endOperation(cm) {
3035 var op = cm.curOp, group = op.ownsGroup;
3036 if (!group) return;
3037
3038 try { fireCallbacksForOps(group); }
3039 finally {
3040 operationGroup = null;
3041 for (var i = 0; i < group.ops.length; i++)
3042 group.ops[i].cm.curOp = null;
3043 endOperations(group);
3044 }
3045 }
3046
3047 // The DOM updates done when an operation finishes are batched so
3048 // that the minimum number of relayouts are required.
3049 function endOperations(group) {
3050 var ops = group.ops;
3051 for (var i = 0; i < ops.length; i++) // Read DOM
3052 endOperation_R1(ops[i]);
3053 for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
3054 endOperation_W1(ops[i]);
3055 for (var i = 0; i < ops.length; i++) // Read DOM
3056 endOperation_R2(ops[i]);
3057 for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
3058 endOperation_W2(ops[i]);
3059 for (var i = 0; i < ops.length; i++) // Read DOM
3060 endOperation_finish(ops[i]);
3061 }
3062
3063 function endOperation_R1(op) {
3064 var cm = op.cm, display = cm.display;
3065 maybeClipScrollbars(cm);
3066 if (op.updateMaxLine) findMaxLine(cm);
3067
3068 op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
3069 op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
3070 op.scrollToPos.to.line >= display.viewTo) ||
3071 display.maxLineChanged && cm.options.lineWrapping;
3072 op.update = op.mustUpdate &&
3073 new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
3074 }
3075
3076 function endOperation_W1(op) {
3077 op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
3078 }
3079
3080 function endOperation_R2(op) {
3081 var cm = op.cm, display = cm.display;
3082 if (op.updatedDisplay) updateHeightsInViewport(cm);
3083
3084 op.barMeasure = measureForScrollbars(cm);
3085
3086 // If the max line changed since it was last measured, measure it,
3087 // and ensure the document's width matches it.
3088 // updateDisplay_W2 will use these properties to do the actual resizing
3089 if (display.maxLineChanged && !cm.options.lineWrapping) {
3090 op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
3091 cm.display.sizerWidth = op.adjustWidthTo;
3092 op.barMeasure.scrollWidth =
3093 Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
3094 op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
3095 }
3096
3097 if (op.updatedDisplay || op.selectionChanged)
3098 op.preparedSelection = display.input.prepareSelection();
3099 }
3100
3101 function endOperation_W2(op) {
3102 var cm = op.cm;
3103
3104 if (op.adjustWidthTo != null) {
3105 cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
3106 if (op.maxScrollLeft < cm.doc.scrollLeft)
3107 setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
3108 cm.display.maxLineChanged = false;
3109 }
3110
3111 if (op.preparedSelection)
3112 cm.display.input.showSelection(op.preparedSelection);
3113 if (op.updatedDisplay)
3114 setDocumentHeight(cm, op.barMeasure);
3115 if (op.updatedDisplay || op.startHeight != cm.doc.height)
3116 updateScrollbars(cm, op.barMeasure);
3117
3118 if (op.selectionChanged) restartBlink(cm);
3119
3120 if (cm.state.focused && op.updateInput)
3121 cm.display.input.reset(op.typing);
3122 if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()))
3123 ensureFocus(op.cm);
3124 }
3125
3126 function endOperation_finish(op) {
3127 var cm = op.cm, display = cm.display, doc = cm.doc;
3128
3129 if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
3130
3131 // Abort mouse wheel delta measurement, when scrolling explicitly
3132 if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
3133 display.wheelStartX = display.wheelStartY = null;
3134
3135 // Propagate the scroll position to the actual DOM scroller
3136 if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
3137 doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
3138 display.scrollbars.setScrollTop(doc.scrollTop);
3139 display.scroller.scrollTop = doc.scrollTop;
3140 }
3141 if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
3142 doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
3143 display.scrollbars.setScrollLeft(doc.scrollLeft);
3144 display.scroller.scrollLeft = doc.scrollLeft;
3145 alignHorizontally(cm);
3146 }
3147 // If we need to scroll a specific position into view, do so.
3148 if (op.scrollToPos) {
3149 var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
3150 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
3151 if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
3152 }
3153
3154 // Fire events for markers that are hidden/unidden by editing or
3155 // undoing
3156 var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
3157 if (hidden) for (var i = 0; i < hidden.length; ++i)
3158 if (!hidden[i].lines.length) signal(hidden[i], "hide");
3159 if (unhidden) for (var i = 0; i < unhidden.length; ++i)
3160 if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
3161
3162 if (display.wrapper.offsetHeight)
3163 doc.scrollTop = cm.display.scroller.scrollTop;
3164
3165 // Fire change events, and delayed event handlers
3166 if (op.changeObjs)
3167 signal(cm, "changes", cm, op.changeObjs);
3168 if (op.update)
3169 op.update.finish();
3170 }
3171
3172 // Run the given function in an operation
3173 function runInOp(cm, f) {
3174 if (cm.curOp) return f();
3175 startOperation(cm);
3176 try { return f(); }
3177 finally { endOperation(cm); }
3178 }
3179 // Wraps a function in an operation. Returns the wrapped function.
3180 function operation(cm, f) {
3181 return function() {
3182 if (cm.curOp) return f.apply(cm, arguments);
3183 startOperation(cm);
3184 try { return f.apply(cm, arguments); }
3185 finally { endOperation(cm); }
3186 };
3187 }
3188 // Used to add methods to editor and doc instances, wrapping them in
3189 // operations.
3190 function methodOp(f) {
3191 return function() {
3192 if (this.curOp) return f.apply(this, arguments);
3193 startOperation(this);
3194 try { return f.apply(this, arguments); }
3195 finally { endOperation(this); }
3196 };
3197 }
3198 function docMethodOp(f) {
3199 return function() {
3200 var cm = this.cm;
3201 if (!cm || cm.curOp) return f.apply(this, arguments);
3202 startOperation(cm);
3203 try { return f.apply(this, arguments); }
3204 finally { endOperation(cm); }
3205 };
3206 }
3207
3208 // VIEW TRACKING
3209
3210 // These objects are used to represent the visible (currently drawn)
3211 // part of the document. A LineView may correspond to multiple
3212 // logical lines, if those are connected by collapsed ranges.
3213 function LineView(doc, line, lineN) {
3214 // The starting line
3215 this.line = line;
3216 // Continuing lines, if any
3217 this.rest = visualLineContinued(line);
3218 // Number of logical lines in this visual line
3219 this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
3220 this.node = this.text = null;
3221 this.hidden = lineIsHidden(doc, line);
3222 }
3223
3224 // Create a range of LineView objects for the given lines.
3225 function buildViewArray(cm, from, to) {
3226 var array = [], nextPos;
3227 for (var pos = from; pos < to; pos = nextPos) {
3228 var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
3229 nextPos = pos + view.size;
3230 array.push(view);
3231 }
3232 return array;
3233 }
3234
3235 // Updates the display.view data structure for a given change to the
3236 // document. From and to are in pre-change coordinates. Lendiff is
3237 // the amount of lines added or subtracted by the change. This is
3238 // used for changes that span multiple lines, or change the way
3239 // lines are divided into visual lines. regLineChange (below)
3240 // registers single-line changes.
3241 function regChange(cm, from, to, lendiff) {
3242 if (from == null) from = cm.doc.first;
3243 if (to == null) to = cm.doc.first + cm.doc.size;
3244 if (!lendiff) lendiff = 0;
3245
3246 var display = cm.display;
3247 if (lendiff && to < display.viewTo &&
3248 (display.updateLineNumbers == null || display.updateLineNumbers > from))
3249 display.updateLineNumbers = from;
3250
3251 cm.curOp.viewChanged = true;
3252
3253 if (from >= display.viewTo) { // Change after
3254 if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
3255 resetView(cm);
3256 } else if (to <= display.viewFrom) { // Change before
3257 if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
3258 resetView(cm);
3259 } else {
3260 display.viewFrom += lendiff;
3261 display.viewTo += lendiff;
3262 }
3263 } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
3264 resetView(cm);
3265 } else if (from <= display.viewFrom) { // Top overlap
3266 var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
3267 if (cut) {
3268 display.view = display.view.slice(cut.index);
3269 display.viewFrom = cut.lineN;
3270 display.viewTo += lendiff;
3271 } else {
3272 resetView(cm);
3273 }
3274 } else if (to >= display.viewTo) { // Bottom overlap
3275 var cut = viewCuttingPoint(cm, from, from, -1);
3276 if (cut) {
3277 display.view = display.view.slice(0, cut.index);
3278 display.viewTo = cut.lineN;
3279 } else {
3280 resetView(cm);
3281 }
3282 } else { // Gap in the middle
3283 var cutTop = viewCuttingPoint(cm, from, from, -1);
3284 var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
3285 if (cutTop && cutBot) {
3286 display.view = display.view.slice(0, cutTop.index)
3287 .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
3288 .concat(display.view.slice(cutBot.index));
3289 display.viewTo += lendiff;
3290 } else {
3291 resetView(cm);
3292 }
3293 }
3294
3295 var ext = display.externalMeasured;
3296 if (ext) {
3297 if (to < ext.lineN)
3298 ext.lineN += lendiff;
3299 else if (from < ext.lineN + ext.size)
3300 display.externalMeasured = null;
3301 }
3302 }
3303
3304 // Register a change to a single line. Type must be one of "text",
3305 // "gutter", "class", "widget"
3306 function regLineChange(cm, line, type) {
3307 cm.curOp.viewChanged = true;
3308 var display = cm.display, ext = cm.display.externalMeasured;
3309 if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
3310 display.externalMeasured = null;
3311
3312 if (line < display.viewFrom || line >= display.viewTo) return;
3313 var lineView = display.view[findViewIndex(cm, line)];
3314 if (lineView.node == null) return;
3315 var arr = lineView.changes || (lineView.changes = []);
3316 if (indexOf(arr, type) == -1) arr.push(type);
3317 }
3318
3319 // Clear the view.
3320 function resetView(cm) {
3321 cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
3322 cm.display.view = [];
3323 cm.display.viewOffset = 0;
3324 }
3325
3326 // Find the view element corresponding to a given line. Return null
3327 // when the line isn't visible.
3328 function findViewIndex(cm, n) {
3329 if (n >= cm.display.viewTo) return null;
3330 n -= cm.display.viewFrom;
3331 if (n < 0) return null;
3332 var view = cm.display.view;
3333 for (var i = 0; i < view.length; i++) {
3334 n -= view[i].size;
3335 if (n < 0) return i;
3336 }
3337 }
3338
3339 function viewCuttingPoint(cm, oldN, newN, dir) {
3340 var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
3341 if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
3342 return {index: index, lineN: newN};
3343 for (var i = 0, n = cm.display.viewFrom; i < index; i++)
3344 n += view[i].size;
3345 if (n != oldN) {
3346 if (dir > 0) {
3347 if (index == view.length - 1) return null;
3348 diff = (n + view[index].size) - oldN;
3349 index++;
3350 } else {
3351 diff = n - oldN;
3352 }
3353 oldN += diff; newN += diff;
3354 }
3355 while (visualLineNo(cm.doc, newN) != newN) {
3356 if (index == (dir < 0 ? 0 : view.length - 1)) return null;
3357 newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
3358 index += dir;
3359 }
3360 return {index: index, lineN: newN};
3361 }
3362
3363 // Force the view to cover a given range, adding empty view element
3364 // or clipping off existing ones as needed.
3365 function adjustView(cm, from, to) {
3366 var display = cm.display, view = display.view;
3367 if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
3368 display.view = buildViewArray(cm, from, to);
3369 display.viewFrom = from;
3370 } else {
3371 if (display.viewFrom > from)
3372 display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
3373 else if (display.viewFrom < from)
3374 display.view = display.view.slice(findViewIndex(cm, from));
3375 display.viewFrom = from;
3376 if (display.viewTo < to)
3377 display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
3378 else if (display.viewTo > to)
3379 display.view = display.view.slice(0, findViewIndex(cm, to));
3380 }
3381 display.viewTo = to;
3382 }
3383
3384 // Count the number of lines in the view whose DOM representation is
3385 // out of date (or nonexistent).
3386 function countDirtyView(cm) {
3387 var view = cm.display.view, dirty = 0;
3388 for (var i = 0; i < view.length; i++) {
3389 var lineView = view[i];
3390 if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
3391 }
3392 return dirty;
3393 }
3394
3395 // EVENT HANDLERS
3396
3397 // Attach the necessary event handlers when initializing the editor
3398 function registerEventHandlers(cm) {
3399 var d = cm.display;
3400 on(d.scroller, "mousedown", operation(cm, onMouseDown));
3401 // Older IE's will not fire a second mousedown for a double click
3402 if (ie && ie_version < 11)
3403 on(d.scroller, "dblclick", operation(cm, function(e) {
3404 if (signalDOMEvent(cm, e)) return;
3405 var pos = posFromMouse(cm, e);
3406 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
3407 e_preventDefault(e);
3408 var word = cm.findWordAt(pos);
3409 extendSelection(cm.doc, word.anchor, word.head);
3410 }));
3411 else
3412 on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
3413 // Some browsers fire contextmenu *after* opening the menu, at
3414 // which point we can't mess with it anymore. Context menu is
3415 // handled in onMouseDown for these browsers.
3416 if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
3417
3418 // Used to suppress mouse event handling when a touch happens
3419 var touchFinished, prevTouch = {end: 0};
3420 function finishTouch() {
3421 if (d.activeTouch) {
3422 touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);
3423 prevTouch = d.activeTouch;
3424 prevTouch.end = +new Date;
3425 }
3426 };
3427 function isMouseLikeTouchEvent(e) {
3428 if (e.touches.length != 1) return false;
3429 var touch = e.touches[0];
3430 return touch.radiusX <= 1 && touch.radiusY <= 1;
3431 }
3432 function farAway(touch, other) {
3433 if (other.left == null) return true;
3434 var dx = other.left - touch.left, dy = other.top - touch.top;
3435 return dx * dx + dy * dy > 20 * 20;
3436 }
3437 on(d.scroller, "touchstart", function(e) {
3438 if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
3439 clearTimeout(touchFinished);
3440 var now = +new Date;
3441 d.activeTouch = {start: now, moved: false,
3442 prev: now - prevTouch.end <= 300 ? prevTouch : null};
3443 if (e.touches.length == 1) {
3444 d.activeTouch.left = e.touches[0].pageX;
3445 d.activeTouch.top = e.touches[0].pageY;
3446 }
3447 }
3448 });
3449 on(d.scroller, "touchmove", function() {
3450 if (d.activeTouch) d.activeTouch.moved = true;
3451 });
3452 on(d.scroller, "touchend", function(e) {
3453 var touch = d.activeTouch;
3454 if (touch && !eventInWidget(d, e) && touch.left != null &&
3455 !touch.moved && new Date - touch.start < 300) {
3456 var pos = cm.coordsChar(d.activeTouch, "page"), range;
3457 if (!touch.prev || farAway(touch, touch.prev)) // Single tap
3458 range = new Range(pos, pos);
3459 else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
3460 range = cm.findWordAt(pos);
3461 else // Triple tap
3462 range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));
3463 cm.setSelection(range.anchor, range.head);
3464 cm.focus();
3465 e_preventDefault(e);
3466 }
3467 finishTouch();
3468 });
3469 on(d.scroller, "touchcancel", finishTouch);
3470
3471 // Sync scrolling between fake scrollbars and real scrollable
3472 // area, ensure viewport is updated when scrolling.
3473 on(d.scroller, "scroll", function() {
3474 if (d.scroller.clientHeight) {
3475 setScrollTop(cm, d.scroller.scrollTop);
3476 setScrollLeft(cm, d.scroller.scrollLeft, true);
3477 signal(cm, "scroll", cm);
3478 }
3479 });
3480
3481 // Listen to wheel events in order to try and update the viewport on time.
3482 on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
3483 on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
3484
3485 // Prevent wrapper from ever scrolling
3486 on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
3487
3488 d.dragFunctions = {
3489 enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
3490 over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
3491 start: function(e){onDragStart(cm, e);},
3492 drop: operation(cm, onDrop),
3493 leave: function() {clearDragCursor(cm);}
3494 };
3495
3496 var inp = d.input.getField();
3497 on(inp, "keyup", function(e) { onKeyUp.call(cm, e); });
3498 on(inp, "keydown", operation(cm, onKeyDown));
3499 on(inp, "keypress", operation(cm, onKeyPress));
3500 on(inp, "focus", bind(onFocus, cm));
3501 on(inp, "blur", bind(onBlur, cm));
3502 }
3503
3504 function dragDropChanged(cm, value, old) {
3505 var wasOn = old && old != CodeMirror.Init;
3506 if (!value != !wasOn) {
3507 var funcs = cm.display.dragFunctions;
3508 var toggle = value ? on : off;
3509 toggle(cm.display.scroller, "dragstart", funcs.start);
3510 toggle(cm.display.scroller, "dragenter", funcs.enter);
3511 toggle(cm.display.scroller, "dragover", funcs.over);
3512 toggle(cm.display.scroller, "dragleave", funcs.leave);
3513 toggle(cm.display.scroller, "drop", funcs.drop);
3514 }
3515 }
3516
3517 // Called when the window resizes
3518 function onResize(cm) {
3519 var d = cm.display;
3520 if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
3521 return;
3522 // Might be a text scaling operation, clear size caches.
3523 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
3524 d.scrollbarsClipped = false;
3525 cm.setSize();
3526 }
3527
3528 // MOUSE EVENTS
3529
3530 // Return true when the given mouse event happened in a widget
3531 function eventInWidget(display, e) {
3532 for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
3533 if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
3534 (n.parentNode == display.sizer && n != display.mover))
3535 return true;
3536 }
3537 }
3538
3539 // Given a mouse event, find the corresponding position. If liberal
3540 // is false, it checks whether a gutter or scrollbar was clicked,
3541 // and returns null if it was. forRect is used by rectangular
3542 // selections, and tries to estimate a character position even for
3543 // coordinates beyond the right of the text.
3544 function posFromMouse(cm, e, liberal, forRect) {
3545 var display = cm.display;
3546 if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null;
3547
3548 var x, y, space = display.lineSpace.getBoundingClientRect();
3549 // Fails unpredictably on IE[67] when mouse is dragged around quickly.
3550 try { x = e.clientX - space.left; y = e.clientY - space.top; }
3551 catch (e) { return null; }
3552 var coords = coordsChar(cm, x, y), line;
3553 if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
3554 var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
3555 coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
3556 }
3557 return coords;
3558 }
3559
3560 // A mouse down can be a single click, double click, triple click,
3561 // start of selection drag, start of text drag, new cursor
3562 // (ctrl-click), rectangle drag (alt-drag), or xwin
3563 // middle-click-paste. Or it might be a click on something we should
3564 // not interfere with, such as a scrollbar or widget.
3565 function onMouseDown(e) {
3566 var cm = this, display = cm.display;
3567 if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return;
3568 display.shift = e.shiftKey;
3569
3570 if (eventInWidget(display, e)) {
3571 if (!webkit) {
3572 // Briefly turn off draggability, to allow widgets to do
3573 // normal dragging things.
3574 display.scroller.draggable = false;
3575 setTimeout(function(){display.scroller.draggable = true;}, 100);
3576 }
3577 return;
3578 }
3579 if (clickInGutter(cm, e)) return;
3580 var start = posFromMouse(cm, e);
3581 window.focus();
3582
3583 switch (e_button(e)) {
3584 case 1:
3585 // #3261: make sure, that we're not starting a second selection
3586 if (cm.state.selectingText)
3587 cm.state.selectingText(e);
3588 else if (start)
3589 leftButtonDown(cm, e, start);
3590 else if (e_target(e) == display.scroller)
3591 e_preventDefault(e);
3592 break;
3593 case 2:
3594 if (webkit) cm.state.lastMiddleDown = +new Date;
3595 if (start) extendSelection(cm.doc, start);
3596 setTimeout(function() {display.input.focus();}, 20);
3597 e_preventDefault(e);
3598 break;
3599 case 3:
3600 if (captureRightClick) onContextMenu(cm, e);
3601 else delayBlurEvent(cm);
3602 break;
3603 }
3604 }
3605
3606 var lastClick, lastDoubleClick;
3607 function leftButtonDown(cm, e, start) {
3608 if (ie) setTimeout(bind(ensureFocus, cm), 0);
3609 else cm.curOp.focus = activeElt();
3610
3611 var now = +new Date, type;
3612 if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
3613 type = "triple";
3614 } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
3615 type = "double";
3616 lastDoubleClick = {time: now, pos: start};
3617 } else {
3618 type = "single";
3619 lastClick = {time: now, pos: start};
3620 }
3621
3622 var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
3623 if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
3624 type == "single" && (contained = sel.contains(start)) > -1 &&
3625 (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
3626 (cmp(contained.to(), start) > 0 || start.xRel < 0))
3627 leftButtonStartDrag(cm, e, start, modifier);
3628 else
3629 leftButtonSelect(cm, e, start, type, modifier);
3630 }
3631
3632 // Start a text drag. When it ends, see if any dragging actually
3633 // happen, and treat as a click if it didn't.
3634 function leftButtonStartDrag(cm, e, start, modifier) {
3635 var display = cm.display, startTime = +new Date;
3636 var dragEnd = operation(cm, function(e2) {
3637 if (webkit) display.scroller.draggable = false;
3638 cm.state.draggingText = false;
3639 off(document, "mouseup", dragEnd);
3640 off(display.scroller, "drop", dragEnd);
3641 if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
3642 e_preventDefault(e2);
3643 if (!modifier && +new Date - 200 < startTime)
3644 extendSelection(cm.doc, start);
3645 // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
3646 if (webkit || ie && ie_version == 9)
3647 setTimeout(function() {document.body.focus(); display.input.focus();}, 20);
3648 else
3649 display.input.focus();
3650 }
3651 });
3652 // Let the drag handler handle this.
3653 if (webkit) display.scroller.draggable = true;
3654 cm.state.draggingText = dragEnd;
3655 // IE's approach to draggable
3656 if (display.scroller.dragDrop) display.scroller.dragDrop();
3657 on(document, "mouseup", dragEnd);
3658 on(display.scroller, "drop", dragEnd);
3659 }
3660
3661 // Normal selection, as opposed to text dragging.
3662 function leftButtonSelect(cm, e, start, type, addNew) {
3663 var display = cm.display, doc = cm.doc;
3664 e_preventDefault(e);
3665
3666 var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
3667 if (addNew && !e.shiftKey) {
3668 ourIndex = doc.sel.contains(start);
3669 if (ourIndex > -1)
3670 ourRange = ranges[ourIndex];
3671 else
3672 ourRange = new Range(start, start);
3673 } else {
3674 ourRange = doc.sel.primary();
3675 ourIndex = doc.sel.primIndex;
3676 }
3677
3678 if (e.altKey) {
3679 type = "rect";
3680 if (!addNew) ourRange = new Range(start, start);
3681 start = posFromMouse(cm, e, true, true);
3682 ourIndex = -1;
3683 } else if (type == "double") {
3684 var word = cm.findWordAt(start);
3685 if (cm.display.shift || doc.extend)
3686 ourRange = extendRange(doc, ourRange, word.anchor, word.head);
3687 else
3688 ourRange = word;
3689 } else if (type == "triple") {
3690 var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
3691 if (cm.display.shift || doc.extend)
3692 ourRange = extendRange(doc, ourRange, line.anchor, line.head);
3693 else
3694 ourRange = line;
3695 } else {
3696 ourRange = extendRange(doc, ourRange, start);
3697 }
3698
3699 if (!addNew) {
3700 ourIndex = 0;
3701 setSelection(doc, new Selection([ourRange], 0), sel_mouse);
3702 startSel = doc.sel;
3703 } else if (ourIndex == -1) {
3704 ourIndex = ranges.length;
3705 setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
3706 {scroll: false, origin: "*mouse"});
3707 } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
3708 setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
3709 {scroll: false, origin: "*mouse"});
3710 startSel = doc.sel;
3711 } else {
3712 replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
3713 }
3714
3715 var lastPos = start;
3716 function extendTo(pos) {
3717 if (cmp(lastPos, pos) == 0) return;
3718 lastPos = pos;
3719
3720 if (type == "rect") {
3721 var ranges = [], tabSize = cm.options.tabSize;
3722 var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
3723 var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
3724 var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
3725 for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
3726 line <= end; line++) {
3727 var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
3728 if (left == right)
3729 ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
3730 else if (text.length > leftPos)
3731 ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
3732 }
3733 if (!ranges.length) ranges.push(new Range(start, start));
3734 setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
3735 {origin: "*mouse", scroll: false});
3736 cm.scrollIntoView(pos);
3737 } else {
3738 var oldRange = ourRange;
3739 var anchor = oldRange.anchor, head = pos;
3740 if (type != "single") {
3741 if (type == "double")
3742 var range = cm.findWordAt(pos);
3743 else
3744 var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
3745 if (cmp(range.anchor, anchor) > 0) {
3746 head = range.head;
3747 anchor = minPos(oldRange.from(), range.anchor);
3748 } else {
3749 head = range.anchor;
3750 anchor = maxPos(oldRange.to(), range.head);
3751 }
3752 }
3753 var ranges = startSel.ranges.slice(0);
3754 ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
3755 setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
3756 }
3757 }
3758
3759 var editorSize = display.wrapper.getBoundingClientRect();
3760 // Used to ensure timeout re-tries don't fire when another extend
3761 // happened in the meantime (clearTimeout isn't reliable -- at
3762 // least on Chrome, the timeouts still happen even when cleared,
3763 // if the clear happens after their scheduled firing time).
3764 var counter = 0;
3765
3766 function extend(e) {
3767 var curCount = ++counter;
3768 var cur = posFromMouse(cm, e, true, type == "rect");
3769 if (!cur) return;
3770 if (cmp(cur, lastPos) != 0) {
3771 cm.curOp.focus = activeElt();
3772 extendTo(cur);
3773 var visible = visibleLines(display, doc);
3774 if (cur.line >= visible.to || cur.line < visible.from)
3775 setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
3776 } else {
3777 var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
3778 if (outside) setTimeout(operation(cm, function() {
3779 if (counter != curCount) return;
3780 display.scroller.scrollTop += outside;
3781 extend(e);
3782 }), 50);
3783 }
3784 }
3785
3786 function done(e) {
3787 cm.state.selectingText = false;
3788 counter = Infinity;
3789 e_preventDefault(e);
3790 display.input.focus();
3791 off(document, "mousemove", move);
3792 off(document, "mouseup", up);
3793 doc.history.lastSelOrigin = null;
3794 }
3795
3796 var move = operation(cm, function(e) {
3797 if (!e_button(e)) done(e);
3798 else extend(e);
3799 });
3800 var up = operation(cm, done);
3801 cm.state.selectingText = up;
3802 on(document, "mousemove", move);
3803 on(document, "mouseup", up);
3804 }
3805
3806 // Determines whether an event happened in the gutter, and fires the
3807 // handlers for the corresponding event.
3808 function gutterEvent(cm, e, type, prevent) {
3809 try { var mX = e.clientX, mY = e.clientY; }
3810 catch(e) { return false; }
3811 if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
3812 if (prevent) e_preventDefault(e);
3813
3814 var display = cm.display;
3815 var lineBox = display.lineDiv.getBoundingClientRect();
3816
3817 if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
3818 mY -= lineBox.top - display.viewOffset;
3819
3820 for (var i = 0; i < cm.options.gutters.length; ++i) {
3821 var g = display.gutters.childNodes[i];
3822 if (g && g.getBoundingClientRect().right >= mX) {
3823 var line = lineAtHeight(cm.doc, mY);
3824 var gutter = cm.options.gutters[i];
3825 signal(cm, type, cm, line, gutter, e);
3826 return e_defaultPrevented(e);
3827 }
3828 }
3829 }
3830
3831 function clickInGutter(cm, e) {
3832 return gutterEvent(cm, e, "gutterClick", true);
3833 }
3834
3835 // Kludge to work around strange IE behavior where it'll sometimes
3836 // re-fire a series of drag-related events right after the drop (#1551)
3837 var lastDrop = 0;
3838
3839 function onDrop(e) {
3840 var cm = this;
3841 clearDragCursor(cm);
3842 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
3843 return;
3844 e_preventDefault(e);
3845 if (ie) lastDrop = +new Date;
3846 var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
3847 if (!pos || cm.isReadOnly()) return;
3848 // Might be a file drop, in which case we simply extract the text
3849 // and insert it.
3850 if (files && files.length && window.FileReader && window.File) {
3851 var n = files.length, text = Array(n), read = 0;
3852 var loadFile = function(file, i) {
3853 if (cm.options.allowDropFileTypes &&
3854 indexOf(cm.options.allowDropFileTypes, file.type) == -1)
3855 return;
3856
3857 var reader = new FileReader;
3858 reader.onload = operation(cm, function() {
3859 var content = reader.result;
3860 if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
3861 text[i] = content;
3862 if (++read == n) {
3863 pos = clipPos(cm.doc, pos);
3864 var change = {from: pos, to: pos,
3865 text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
3866 origin: "paste"};
3867 makeChange(cm.doc, change);
3868 setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
3869 }
3870 });
3871 reader.readAsText(file);
3872 };
3873 for (var i = 0; i < n; ++i) loadFile(files[i], i);
3874 } else { // Normal drop
3875 // Don't do a replace if the drop happened inside of the selected text.
3876 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
3877 cm.state.draggingText(e);
3878 // Ensure the editor is re-focused
3879 setTimeout(function() {cm.display.input.focus();}, 20);
3880 return;
3881 }
3882 try {
3883 var text = e.dataTransfer.getData("Text");
3884 if (text) {
3885 if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey))
3886 var selected = cm.listSelections();
3887 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
3888 if (selected) for (var i = 0; i < selected.length; ++i)
3889 replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
3890 cm.replaceSelection(text, "around", "paste");
3891 cm.display.input.focus();
3892 }
3893 }
3894 catch(e){}
3895 }
3896 }
3897
3898 function onDragStart(cm, e) {
3899 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
3900 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
3901
3902 e.dataTransfer.setData("Text", cm.getSelection());
3903
3904 // Use dummy image instead of default browsers image.
3905 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
3906 if (e.dataTransfer.setDragImage && !safari) {
3907 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
3908 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
3909 if (presto) {
3910 img.width = img.height = 1;
3911 cm.display.wrapper.appendChild(img);
3912 // Force a relayout, or Opera won't use our image for some obscure reason
3913 img._top = img.offsetTop;
3914 }
3915 e.dataTransfer.setDragImage(img, 0, 0);
3916 if (presto) img.parentNode.removeChild(img);
3917 }
3918 }
3919
3920 function onDragOver(cm, e) {
3921 var pos = posFromMouse(cm, e);
3922 if (!pos) return;
3923 var frag = document.createDocumentFragment();
3924 drawSelectionCursor(cm, pos, frag);
3925 if (!cm.display.dragCursor) {
3926 cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
3927 cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
3928 }
3929 removeChildrenAndAdd(cm.display.dragCursor, frag);
3930 }
3931
3932 function clearDragCursor(cm) {
3933 if (cm.display.dragCursor) {
3934 cm.display.lineSpace.removeChild(cm.display.dragCursor);
3935 cm.display.dragCursor = null;
3936 }
3937 }
3938
3939 // SCROLL EVENTS
3940
3941 // Sync the scrollable area and scrollbars, ensure the viewport
3942 // covers the visible area.
3943 function setScrollTop(cm, val) {
3944 if (Math.abs(cm.doc.scrollTop - val) < 2) return;
3945 cm.doc.scrollTop = val;
3946 if (!gecko) updateDisplaySimple(cm, {top: val});
3947 if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
3948 cm.display.scrollbars.setScrollTop(val);
3949 if (gecko) updateDisplaySimple(cm);
3950 startWorker(cm, 100);
3951 }
3952 // Sync scroller and scrollbar, ensure the gutter elements are
3953 // aligned.
3954 function setScrollLeft(cm, val, isScroller) {
3955 if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
3956 val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
3957 cm.doc.scrollLeft = val;
3958 alignHorizontally(cm);
3959 if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
3960 cm.display.scrollbars.setScrollLeft(val);
3961 }
3962
3963 // Since the delta values reported on mouse wheel events are
4433 // Since the delta values reported on mouse wheel events are
3964 // unstandardized between browsers and even browser versions, and
4434 // unstandardized between browsers and even browser versions, and
3965 // generally horribly unpredictable, this code starts by measuring
4435 // generally horribly unpredictable, this code starts by measuring
@@ -3976,24 +4446,24 b''
3976 // know one. These don't have to be accurate -- the result of them
4446 // know one. These don't have to be accurate -- the result of them
3977 // being wrong would just be a slight flicker on the first wheel
4447 // being wrong would just be a slight flicker on the first wheel
3978 // scroll (if it is large enough).
4448 // scroll (if it is large enough).
3979 if (ie) wheelPixelsPerUnit = -.53;
4449 if (ie) { wheelPixelsPerUnit = -.53; }
3980 else if (gecko) wheelPixelsPerUnit = 15;
4450 else if (gecko) { wheelPixelsPerUnit = 15; }
3981 else if (chrome) wheelPixelsPerUnit = -.7;
4451 else if (chrome) { wheelPixelsPerUnit = -.7; }
3982 else if (safari) wheelPixelsPerUnit = -1/3;
4452 else if (safari) { wheelPixelsPerUnit = -1/3; }
3983
4453
3984 var wheelEventDelta = function(e) {
4454 function wheelEventDelta(e) {
3985 var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
4455 var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
3986 if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
4456 if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
3987 if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
4457 if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
3988 else if (dy == null) dy = e.wheelDelta;
4458 else if (dy == null) { dy = e.wheelDelta; }
3989 return {x: dx, y: dy};
4459 return {x: dx, y: dy}
3990 };
4460 }
3991 CodeMirror.wheelEventPixels = function(e) {
4461 function wheelEventPixels(e) {
3992 var delta = wheelEventDelta(e);
4462 var delta = wheelEventDelta(e);
3993 delta.x *= wheelPixelsPerUnit;
4463 delta.x *= wheelPixelsPerUnit;
3994 delta.y *= wheelPixelsPerUnit;
4464 delta.y *= wheelPixelsPerUnit;
3995 return delta;
4465 return delta
3996 };
4466 }
3997
4467
3998 function onScrollWheel(cm, e) {
4468 function onScrollWheel(cm, e) {
3999 var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
4469 var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
@@ -4002,7 +4472,7 b''
4002 // Quit if there's nothing to scroll here
4472 // Quit if there's nothing to scroll here
4003 var canScrollX = scroll.scrollWidth > scroll.clientWidth;
4473 var canScrollX = scroll.scrollWidth > scroll.clientWidth;
4004 var canScrollY = scroll.scrollHeight > scroll.clientHeight;
4474 var canScrollY = scroll.scrollHeight > scroll.clientHeight;
4005 if (!(dx && canScrollX || dy && canScrollY)) return;
4475 if (!(dx && canScrollX || dy && canScrollY)) { return }
4006
4476
4007 // Webkit browsers on OS X abort momentum scrolls when the target
4477 // Webkit browsers on OS X abort momentum scrolls when the target
4008 // of the scroll event is removed from the scrollable element.
4478 // of the scroll event is removed from the scrollable element.
@@ -4013,7 +4483,7 b''
4013 for (var i = 0; i < view.length; i++) {
4483 for (var i = 0; i < view.length; i++) {
4014 if (view[i].node == cur) {
4484 if (view[i].node == cur) {
4015 cm.display.currentWheelTarget = cur;
4485 cm.display.currentWheelTarget = cur;
4016 break outer;
4486 break outer
4017 }
4487 }
4018 }
4488 }
4019 }
4489 }
@@ -4027,16 +4497,16 b''
4027 // better than glitching out.
4497 // better than glitching out.
4028 if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
4498 if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
4029 if (dy && canScrollY)
4499 if (dy && canScrollY)
4030 setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
4500 { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
4031 setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
4501 setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
4032 // Only prevent default scrolling if vertical scrolling is
4502 // Only prevent default scrolling if vertical scrolling is
4033 // actually possible. Otherwise, it causes vertical scroll
4503 // actually possible. Otherwise, it causes vertical scroll
4034 // jitter on OSX trackpads when deltaX is small and deltaY
4504 // jitter on OSX trackpads when deltaX is small and deltaY
4035 // is large (issue #3579)
4505 // is large (issue #3579)
4036 if (!dy || (dy && canScrollY))
4506 if (!dy || (dy && canScrollY))
4037 e_preventDefault(e);
4507 { e_preventDefault(e); }
4038 display.wheelStartX = null; // Abort measurement, if in progress
4508 display.wheelStartX = null; // Abort measurement, if in progress
4039 return;
4509 return
4040 }
4510 }
4041
4511
4042 // 'Project' the visible viewport to cover the area that is being
4512 // 'Project' the visible viewport to cover the area that is being
@@ -4044,8 +4514,8 b''
4044 if (dy && wheelPixelsPerUnit != null) {
4514 if (dy && wheelPixelsPerUnit != null) {
4045 var pixels = dy * wheelPixelsPerUnit;
4515 var pixels = dy * wheelPixelsPerUnit;
4046 var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
4516 var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
4047 if (pixels < 0) top = Math.max(0, top + pixels - 50);
4517 if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
4048 else bot = Math.min(cm.doc.height, bot + pixels + 50);
4518 else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
4049 updateDisplaySimple(cm, {top: top, bottom: bot});
4519 updateDisplaySimple(cm, {top: top, bottom: bot});
4050 }
4520 }
4051
4521
@@ -4054,13 +4524,13 b''
4054 display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
4524 display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
4055 display.wheelDX = dx; display.wheelDY = dy;
4525 display.wheelDX = dx; display.wheelDY = dy;
4056 setTimeout(function() {
4526 setTimeout(function() {
4057 if (display.wheelStartX == null) return;
4527 if (display.wheelStartX == null) { return }
4058 var movedX = scroll.scrollLeft - display.wheelStartX;
4528 var movedX = scroll.scrollLeft - display.wheelStartX;
4059 var movedY = scroll.scrollTop - display.wheelStartY;
4529 var movedY = scroll.scrollTop - display.wheelStartY;
4060 var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
4530 var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
4061 (movedX && display.wheelDX && movedX / display.wheelDX);
4531 (movedX && display.wheelDX && movedX / display.wheelDX);
4062 display.wheelStartX = display.wheelStartY = null;
4532 display.wheelStartX = display.wheelStartY = null;
4063 if (!sample) return;
4533 if (!sample) { return }
4064 wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
4534 wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
4065 ++wheelSamples;
4535 ++wheelSamples;
4066 }, 200);
4536 }, 200);
@@ -4070,226 +4540,109 b''
4070 }
4540 }
4071 }
4541 }
4072
4542
4073 // KEY EVENTS
4543 // Selection objects are immutable. A new one is created every time
4074
4544 // the selection changes. A selection is one or more non-overlapping
4075 // Run a handler that was bound to a key.
4545 // (and non-touching) ranges, sorted, and an integer that indicates
4076 function doHandleBinding(cm, bound, dropShift) {
4546 // which one is the primary selection (the one that's scrolled into
4077 if (typeof bound == "string") {
4547 // view, that getCursor returns, etc).
4078 bound = commands[bound];
4548 var Selection = function(ranges, primIndex) {
4079 if (!bound) return false;
4549 this.ranges = ranges;
4080 }
4550 this.primIndex = primIndex;
4081 // Ensure previous input has been read, so that the handler sees a
4551 };
4082 // consistent view of the document
4552
4083 cm.display.input.ensurePolled();
4553 Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
4084 var prevShift = cm.display.shift, done = false;
4554
4085 try {
4555 Selection.prototype.equals = function (other) {
4086 if (cm.isReadOnly()) cm.state.suppressEdits = true;
4556 var this$1 = this;
4087 if (dropShift) cm.display.shift = false;
4557
4088 done = bound(cm) != Pass;
4558 if (other == this) { return true }
4089 } finally {
4559 if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
4090 cm.display.shift = prevShift;
4560 for (var i = 0; i < this.ranges.length; i++) {
4091 cm.state.suppressEdits = false;
4561 var here = this$1.ranges[i], there = other.ranges[i];
4092 }
4562 if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
4093 return done;
4563 }
4094 }
4564 return true
4095
4565 };
4096 function lookupKeyForEditor(cm, name, handle) {
4566
4097 for (var i = 0; i < cm.state.keyMaps.length; i++) {
4567 Selection.prototype.deepCopy = function () {
4098 var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
4568 var this$1 = this;
4099 if (result) return result;
4569
4100 }
4570 var out = [];
4101 return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
4571 for (var i = 0; i < this.ranges.length; i++)
4102 || lookupKey(name, cm.options.keyMap, handle, cm);
4572 { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }
4103 }
4573 return new Selection(out, this.primIndex)
4104
4574 };
4105 var stopSeq = new Delayed;
4575
4106 function dispatchKey(cm, name, e, handle) {
4576 Selection.prototype.somethingSelected = function () {
4107 var seq = cm.state.keySeq;
4577 var this$1 = this;
4108 if (seq) {
4578
4109 if (isModifierKey(name)) return "handled";
4579 for (var i = 0; i < this.ranges.length; i++)
4110 stopSeq.set(50, function() {
4580 { if (!this$1.ranges[i].empty()) { return true } }
4111 if (cm.state.keySeq == seq) {
4581 return false
4112 cm.state.keySeq = null;
4582 };
4113 cm.display.input.reset();
4583
4114 }
4584 Selection.prototype.contains = function (pos, end) {
4115 });
4585 var this$1 = this;
4116 name = seq + " " + name;
4586
4117 }
4587 if (!end) { end = pos; }
4118 var result = lookupKeyForEditor(cm, name, handle);
4588 for (var i = 0; i < this.ranges.length; i++) {
4119
4589 var range = this$1.ranges[i];
4120 if (result == "multi")
4590 if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
4121 cm.state.keySeq = name;
4591 { return i }
4122 if (result == "handled")
4592 }
4123 signalLater(cm, "keyHandled", cm, name, e);
4593 return -1
4124
4594 };
4125 if (result == "handled" || result == "multi") {
4595
4126 e_preventDefault(e);
4596 var Range = function(anchor, head) {
4127 restartBlink(cm);
4597 this.anchor = anchor; this.head = head;
4128 }
4598 };
4129
4599
4130 if (seq && !result && /\'$/.test(name)) {
4600 Range.prototype.from = function () { return minPos(this.anchor, this.head) };
4131 e_preventDefault(e);
4601 Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
4132 return true;
4602 Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
4133 }
4603
4134 return !!result;
4604 // Take an unsorted, potentially overlapping set of ranges, and
4135 }
4605 // build a selection out of it. 'Consumes' ranges array (modifying
4136
4606 // it).
4137 // Handle a key from the keydown event.
4607 function normalizeSelection(cm, ranges, primIndex) {
4138 function handleKeyBinding(cm, e) {
4608 var mayTouch = cm && cm.options.selectionsMayTouch;
4139 var name = keyName(e, true);
4609 var prim = ranges[primIndex];
4140 if (!name) return false;
4610 ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
4141
4611 primIndex = indexOf(ranges, prim);
4142 if (e.shiftKey && !cm.state.keySeq) {
4612 for (var i = 1; i < ranges.length; i++) {
4143 // First try to resolve full name (including 'Shift-'). Failing
4613 var cur = ranges[i], prev = ranges[i - 1];
4144 // that, see if there is a cursor-motion command (starting with
4614 var diff = cmp(prev.to(), cur.from());
4145 // 'go') bound to the keyname without 'Shift-'.
4615 if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) {
4146 return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);})
4616 var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
4147 || dispatchKey(cm, name, e, function(b) {
4617 var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
4148 if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
4618 if (i <= primIndex) { --primIndex; }
4149 return doHandleBinding(cm, b);
4619 ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
4150 });
4620 }
4151 } else {
4621 }
4152 return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });
4622 return new Selection(ranges, primIndex)
4153 }
4623 }
4154 }
4624
4155
4625 function simpleSelection(anchor, head) {
4156 // Handle a key from the keypress event
4626 return new Selection([new Range(anchor, head || anchor)], 0)
4157 function handleCharBinding(cm, e, ch) {
4627 }
4158 return dispatchKey(cm, "'" + ch + "'", e,
4159 function(b) { return doHandleBinding(cm, b, true); });
4160 }
4161
4162 var lastStoppedKey = null;
4163 function onKeyDown(e) {
4164 var cm = this;
4165 cm.curOp.focus = activeElt();
4166 if (signalDOMEvent(cm, e)) return;
4167 // IE does strange things with escape.
4168 if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
4169 var code = e.keyCode;
4170 cm.display.shift = code == 16 || e.shiftKey;
4171 var handled = handleKeyBinding(cm, e);
4172 if (presto) {
4173 lastStoppedKey = handled ? code : null;
4174 // Opera has no cut event... we try to at least catch the key combo
4175 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
4176 cm.replaceSelection("", null, "cut");
4177 }
4178
4179 // Turn mouse into crosshair when Alt is held on Mac.
4180 if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
4181 showCrossHair(cm);
4182 }
4183
4184 function showCrossHair(cm) {
4185 var lineDiv = cm.display.lineDiv;
4186 addClass(lineDiv, "CodeMirror-crosshair");
4187
4188 function up(e) {
4189 if (e.keyCode == 18 || !e.altKey) {
4190 rmClass(lineDiv, "CodeMirror-crosshair");
4191 off(document, "keyup", up);
4192 off(document, "mouseover", up);
4193 }
4194 }
4195 on(document, "keyup", up);
4196 on(document, "mouseover", up);
4197 }
4198
4199 function onKeyUp(e) {
4200 if (e.keyCode == 16) this.doc.sel.shift = false;
4201 signalDOMEvent(this, e);
4202 }
4203
4204 function onKeyPress(e) {
4205 var cm = this;
4206 if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
4207 var keyCode = e.keyCode, charCode = e.charCode;
4208 if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
4209 if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;
4210 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
4211 if (handleCharBinding(cm, e, ch)) return;
4212 cm.display.input.onKeyPress(e);
4213 }
4214
4215 // FOCUS/BLUR EVENTS
4216
4217 function delayBlurEvent(cm) {
4218 cm.state.delayingBlurEvent = true;
4219 setTimeout(function() {
4220 if (cm.state.delayingBlurEvent) {
4221 cm.state.delayingBlurEvent = false;
4222 onBlur(cm);
4223 }
4224 }, 100);
4225 }
4226
4227 function onFocus(cm) {
4228 if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;
4229
4230 if (cm.options.readOnly == "nocursor") return;
4231 if (!cm.state.focused) {
4232 signal(cm, "focus", cm);
4233 cm.state.focused = true;
4234 addClass(cm.display.wrapper, "CodeMirror-focused");
4235 // This test prevents this from firing when a context
4236 // menu is closed (since the input reset would kill the
4237 // select-all detection hack)
4238 if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
4239 cm.display.input.reset();
4240 if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730
4241 }
4242 cm.display.input.receivedFocus();
4243 }
4244 restartBlink(cm);
4245 }
4246 function onBlur(cm) {
4247 if (cm.state.delayingBlurEvent) return;
4248
4249 if (cm.state.focused) {
4250 signal(cm, "blur", cm);
4251 cm.state.focused = false;
4252 rmClass(cm.display.wrapper, "CodeMirror-focused");
4253 }
4254 clearInterval(cm.display.blinker);
4255 setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
4256 }
4257
4258 // CONTEXT MENU HANDLING
4259
4260 // To make the context menu work, we need to briefly unhide the
4261 // textarea (making it as unobtrusive as possible) to let the
4262 // right-click take effect on it.
4263 function onContextMenu(cm, e) {
4264 if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
4265 if (signalDOMEvent(cm, e, "contextmenu")) return;
4266 cm.display.input.onContextMenu(e);
4267 }
4268
4269 function contextMenuInGutter(cm, e) {
4270 if (!hasHandler(cm, "gutterContextMenu")) return false;
4271 return gutterEvent(cm, e, "gutterContextMenu", false);
4272 }
4273
4274 // UPDATING
4275
4628
4276 // Compute the position of the end of a change (its 'to' property
4629 // Compute the position of the end of a change (its 'to' property
4277 // refers to the pre-change end).
4630 // refers to the pre-change end).
4278 var changeEnd = CodeMirror.changeEnd = function(change) {
4631 function changeEnd(change) {
4279 if (!change.text) return change.to;
4632 if (!change.text) { return change.to }
4280 return Pos(change.from.line + change.text.length - 1,
4633 return Pos(change.from.line + change.text.length - 1,
4281 lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
4634 lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
4282 };
4635 }
4283
4636
4284 // Adjust a position to refer to the post-change position of the
4637 // Adjust a position to refer to the post-change position of the
4285 // same text, or the end of the change if the change covers it.
4638 // same text, or the end of the change if the change covers it.
4286 function adjustForChange(pos, change) {
4639 function adjustForChange(pos, change) {
4287 if (cmp(pos, change.from) < 0) return pos;
4640 if (cmp(pos, change.from) < 0) { return pos }
4288 if (cmp(pos, change.to) <= 0) return changeEnd(change);
4641 if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
4289
4642
4290 var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
4643 var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
4291 if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
4644 if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
4292 return Pos(line, ch);
4645 return Pos(line, ch)
4293 }
4646 }
4294
4647
4295 function computeSelAfterChange(doc, change) {
4648 function computeSelAfterChange(doc, change) {
@@ -4299,14 +4652,14 b''
4299 out.push(new Range(adjustForChange(range.anchor, change),
4652 out.push(new Range(adjustForChange(range.anchor, change),
4300 adjustForChange(range.head, change)));
4653 adjustForChange(range.head, change)));
4301 }
4654 }
4302 return normalizeSelection(out, doc.sel.primIndex);
4655 return normalizeSelection(doc.cm, out, doc.sel.primIndex)
4303 }
4656 }
4304
4657
4305 function offsetPos(pos, old, nw) {
4658 function offsetPos(pos, old, nw) {
4306 if (pos.line == old.line)
4659 if (pos.line == old.line)
4307 return Pos(nw.line, pos.ch - old.ch + nw.ch);
4660 { return Pos(nw.line, pos.ch - old.ch + nw.ch) }
4308 else
4661 else
4309 return Pos(nw.line + (pos.line - old.line), pos.ch);
4662 { return Pos(nw.line + (pos.line - old.line), pos.ch) }
4310 }
4663 }
4311
4664
4312 // Used by replaceSelections to allow moving the selection to the
4665 // Used by replaceSelections to allow moving the selection to the
@@ -4327,2823 +4680,25 b''
4327 out[i] = new Range(from, from);
4680 out[i] = new Range(from, from);
4328 }
4681 }
4329 }
4682 }
4330 return new Selection(out, doc.sel.primIndex);
4683 return new Selection(out, doc.sel.primIndex)
4331 }
4684 }
4332
4685
4333 // Allow "beforeChange" event handlers to influence a change
4686 // Used to get the editor into a consistent state again when options change.
4334 function filterChange(doc, change, update) {
4687
4335 var obj = {
4688 function loadMode(cm) {
4336 canceled: false,
4689 cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
4337 from: change.from,
4338 to: change.to,
4339 text: change.text,
4340 origin: change.origin,
4341 cancel: function() { this.canceled = true; }
4342 };
4343 if (update) obj.update = function(from, to, text, origin) {
4344 if (from) this.from = clipPos(doc, from);
4345 if (to) this.to = clipPos(doc, to);
4346 if (text) this.text = text;
4347 if (origin !== undefined) this.origin = origin;
4348 };
4349 signal(doc, "beforeChange", doc, obj);
4350 if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
4351
4352 if (obj.canceled) return null;
4353 return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
4354 }
4355
4356 // Apply a change to a document, and add it to the document's
4357 // history, and propagating it to all linked documents.
4358 function makeChange(doc, change, ignoreReadOnly) {
4359 if (doc.cm) {
4360 if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
4361 if (doc.cm.state.suppressEdits) return;
4362 }
4363
4364 if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
4365 change = filterChange(doc, change, true);
4366 if (!change) return;
4367 }
4368
4369 // Possibly split or suppress the update based on the presence
4370 // of read-only spans in its range.
4371 var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
4372 if (split) {
4373 for (var i = split.length - 1; i >= 0; --i)
4374 makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
4375 } else {
4376 makeChangeInner(doc, change);
4377 }
4378 }
4379
4380 function makeChangeInner(doc, change) {
4381 if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
4382 var selAfter = computeSelAfterChange(doc, change);
4383 addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
4384
4385 makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
4386 var rebased = [];
4387
4388 linkedDocs(doc, function(doc, sharedHist) {
4389 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
4390 rebaseHist(doc.history, change);
4391 rebased.push(doc.history);
4392 }
4393 makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
4394 });
4395 }
4396
4397 // Revert a change stored in a document's history.
4398 function makeChangeFromHistory(doc, type, allowSelectionOnly) {
4399 if (doc.cm && doc.cm.state.suppressEdits) return;
4400
4401 var hist = doc.history, event, selAfter = doc.sel;
4402 var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
4403
4404 // Verify that there is a useable event (so that ctrl-z won't
4405 // needlessly clear selection events)
4406 for (var i = 0; i < source.length; i++) {
4407 event = source[i];
4408 if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
4409 break;
4410 }
4411 if (i == source.length) return;
4412 hist.lastOrigin = hist.lastSelOrigin = null;
4413
4414 for (;;) {
4415 event = source.pop();
4416 if (event.ranges) {
4417 pushSelectionToHistory(event, dest);
4418 if (allowSelectionOnly && !event.equals(doc.sel)) {
4419 setSelection(doc, event, {clearRedo: false});
4420 return;
4421 }
4422 selAfter = event;
4423 }
4424 else break;
4425 }
4426
4427 // Build up a reverse change object to add to the opposite history
4428 // stack (redo when undoing, and vice versa).
4429 var antiChanges = [];
4430 pushSelectionToHistory(selAfter, dest);
4431 dest.push({changes: antiChanges, generation: hist.generation});
4432 hist.generation = event.generation || ++hist.maxGeneration;
4433
4434 var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
4435
4436 for (var i = event.changes.length - 1; i >= 0; --i) {
4437 var change = event.changes[i];
4438 change.origin = type;
4439 if (filter && !filterChange(doc, change, false)) {
4440 source.length = 0;
4441 return;
4442 }
4443
4444 antiChanges.push(historyChangeFromChange(doc, change));
4445
4446 var after = i ? computeSelAfterChange(doc, change) : lst(source);
4447 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
4448 if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
4449 var rebased = [];
4450
4451 // Propagate to the linked documents
4452 linkedDocs(doc, function(doc, sharedHist) {
4453 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
4454 rebaseHist(doc.history, change);
4455 rebased.push(doc.history);
4456 }
4457 makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
4458 });
4459 }
4460 }
4461
4462 // Sub-views need their line numbers shifted when text is added
4463 // above or below them in the parent document.
4464 function shiftDoc(doc, distance) {
4465 if (distance == 0) return;
4466 doc.first += distance;
4467 doc.sel = new Selection(map(doc.sel.ranges, function(range) {
4468 return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
4469 Pos(range.head.line + distance, range.head.ch));
4470 }), doc.sel.primIndex);
4471 if (doc.cm) {
4472 regChange(doc.cm, doc.first, doc.first - distance, distance);
4473 for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
4474 regLineChange(doc.cm, l, "gutter");
4475 }
4476 }
4477
4478 // More lower-level change function, handling only a single document
4479 // (not linked ones).
4480 function makeChangeSingleDoc(doc, change, selAfter, spans) {
4481 if (doc.cm && !doc.cm.curOp)
4482 return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
4483
4484 if (change.to.line < doc.first) {
4485 shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
4486 return;
4487 }
4488 if (change.from.line > doc.lastLine()) return;
4489
4490 // Clip the change to the size of this doc
4491 if (change.from.line < doc.first) {
4492 var shift = change.text.length - 1 - (doc.first - change.from.line);
4493 shiftDoc(doc, shift);
4494 change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
4495 text: [lst(change.text)], origin: change.origin};
4496 }
4497 var last = doc.lastLine();
4498 if (change.to.line > last) {
4499 change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
4500 text: [change.text[0]], origin: change.origin};
4501 }
4502
4503 change.removed = getBetween(doc, change.from, change.to);
4504
4505 if (!selAfter) selAfter = computeSelAfterChange(doc, change);
4506 if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
4507 else updateDoc(doc, change, spans);
4508 setSelectionNoUndo(doc, selAfter, sel_dontScroll);
4509 }
4510
4511 // Handle the interaction of a change to a document with the editor
4512 // that this document is part of.
4513 function makeChangeSingleDocInEditor(cm, change, spans) {
4514 var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
4515
4516 var recomputeMaxLength = false, checkWidthStart = from.line;
4517 if (!cm.options.lineWrapping) {
4518 checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
4519 doc.iter(checkWidthStart, to.line + 1, function(line) {
4520 if (line == display.maxLine) {
4521 recomputeMaxLength = true;
4522 return true;
4523 }
4524 });
4525 }
4526
4527 if (doc.sel.contains(change.from, change.to) > -1)
4528 signalCursorActivity(cm);
4529
4530 updateDoc(doc, change, spans, estimateHeight(cm));
4531
4532 if (!cm.options.lineWrapping) {
4533 doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
4534 var len = lineLength(line);
4535 if (len > display.maxLineLength) {
4536 display.maxLine = line;
4537 display.maxLineLength = len;
4538 display.maxLineChanged = true;
4539 recomputeMaxLength = false;
4540 }
4541 });
4542 if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
4543 }
4544
4545 // Adjust frontier, schedule worker
4546 doc.frontier = Math.min(doc.frontier, from.line);
4547 startWorker(cm, 400);
4548
4549 var lendiff = change.text.length - (to.line - from.line) - 1;
4550 // Remember that these lines changed, for updating the display
4551 if (change.full)
4552 regChange(cm);
4553 else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
4554 regLineChange(cm, from.line, "text");
4555 else
4556 regChange(cm, from.line, to.line + 1, lendiff);
4557
4558 var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
4559 if (changeHandler || changesHandler) {
4560 var obj = {
4561 from: from, to: to,
4562 text: change.text,
4563 removed: change.removed,
4564 origin: change.origin
4565 };
4566 if (changeHandler) signalLater(cm, "change", cm, obj);
4567 if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
4568 }
4569 cm.display.selForContextMenu = null;
4570 }
4571
4572 function replaceRange(doc, code, from, to, origin) {
4573 if (!to) to = from;
4574 if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
4575 if (typeof code == "string") code = doc.splitLines(code);
4576 makeChange(doc, {from: from, to: to, text: code, origin: origin});
4577 }
4578
4579 // SCROLLING THINGS INTO VIEW
4580
4581 // If an editor sits on the top or bottom of the window, partially
4582 // scrolled out of view, this ensures that the cursor is visible.
4583 function maybeScrollWindow(cm, coords) {
4584 if (signalDOMEvent(cm, "scrollCursorIntoView")) return;
4585
4586 var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
4587 if (coords.top + box.top < 0) doScroll = true;
4588 else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
4589 if (doScroll != null && !phantom) {
4590 var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
4591 (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
4592 (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
4593 coords.left + "px; width: 2px;");
4594 cm.display.lineSpace.appendChild(scrollNode);
4595 scrollNode.scrollIntoView(doScroll);
4596 cm.display.lineSpace.removeChild(scrollNode);
4597 }
4598 }
4599
4600 // Scroll a given position into view (immediately), verifying that
4601 // it actually became visible (as line heights are accurately
4602 // measured, the position of something may 'drift' during drawing).
4603 function scrollPosIntoView(cm, pos, end, margin) {
4604 if (margin == null) margin = 0;
4605 for (var limit = 0; limit < 5; limit++) {
4606 var changed = false, coords = cursorCoords(cm, pos);
4607 var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
4608 var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
4609 Math.min(coords.top, endCoords.top) - margin,
4610 Math.max(coords.left, endCoords.left),
4611 Math.max(coords.bottom, endCoords.bottom) + margin);
4612 var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
4613 if (scrollPos.scrollTop != null) {
4614 setScrollTop(cm, scrollPos.scrollTop);
4615 if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
4616 }
4617 if (scrollPos.scrollLeft != null) {
4618 setScrollLeft(cm, scrollPos.scrollLeft);
4619 if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
4620 }
4621 if (!changed) break;
4622 }
4623 return coords;
4624 }
4625
4626 // Scroll a given set of coordinates into view (immediately).
4627 function scrollIntoView(cm, x1, y1, x2, y2) {
4628 var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
4629 if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
4630 if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
4631 }
4632
4633 // Calculate a new scroll position needed to scroll the given
4634 // rectangle into view. Returns an object with scrollTop and
4635 // scrollLeft properties. When these are undefined, the
4636 // vertical/horizontal position does not need to be adjusted.
4637 function calculateScrollPos(cm, x1, y1, x2, y2) {
4638 var display = cm.display, snapMargin = textHeight(cm.display);
4639 if (y1 < 0) y1 = 0;
4640 var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
4641 var screen = displayHeight(cm), result = {};
4642 if (y2 - y1 > screen) y2 = y1 + screen;
4643 var docBottom = cm.doc.height + paddingVert(display);
4644 var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
4645 if (y1 < screentop) {
4646 result.scrollTop = atTop ? 0 : y1;
4647 } else if (y2 > screentop + screen) {
4648 var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
4649 if (newTop != screentop) result.scrollTop = newTop;
4650 }
4651
4652 var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
4653 var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
4654 var tooWide = x2 - x1 > screenw;
4655 if (tooWide) x2 = x1 + screenw;
4656 if (x1 < 10)
4657 result.scrollLeft = 0;
4658 else if (x1 < screenleft)
4659 result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
4660 else if (x2 > screenw + screenleft - 3)
4661 result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
4662 return result;
4663 }
4664
4665 // Store a relative adjustment to the scroll position in the current
4666 // operation (to be applied when the operation finishes).
4667 function addToScrollPos(cm, left, top) {
4668 if (left != null || top != null) resolveScrollToPos(cm);
4669 if (left != null)
4670 cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
4671 if (top != null)
4672 cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
4673 }
4674
4675 // Make sure that at the end of the operation the current cursor is
4676 // shown.
4677 function ensureCursorVisible(cm) {
4678 resolveScrollToPos(cm);
4679 var cur = cm.getCursor(), from = cur, to = cur;
4680 if (!cm.options.lineWrapping) {
4681 from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
4682 to = Pos(cur.line, cur.ch + 1);
4683 }
4684 cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
4685 }
4686
4687 // When an operation has its scrollToPos property set, and another
4688 // scroll action is applied before the end of the operation, this
4689 // 'simulates' scrolling that position into view in a cheap way, so
4690 // that the effect of intermediate scroll commands is not ignored.
4691 function resolveScrollToPos(cm) {
4692 var range = cm.curOp.scrollToPos;
4693 if (range) {
4694 cm.curOp.scrollToPos = null;
4695 var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
4696 var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
4697 Math.min(from.top, to.top) - range.margin,
4698 Math.max(from.right, to.right),
4699 Math.max(from.bottom, to.bottom) + range.margin);
4700 cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
4701 }
4702 }
4703
4704 // API UTILITIES
4705
4706 // Indent the given line. The how parameter can be "smart",
4707 // "add"/null, "subtract", or "prev". When aggressive is false
4708 // (typically set to true for forced single-line indents), empty
4709 // lines are not indented, and places where the mode returns Pass
4710 // are left alone.
4711 function indentLine(cm, n, how, aggressive) {
4712 var doc = cm.doc, state;
4713 if (how == null) how = "add";
4714 if (how == "smart") {
4715 // Fall back to "prev" when the mode doesn't have an indentation
4716 // method.
4717 if (!doc.mode.indent) how = "prev";
4718 else state = getStateBefore(cm, n);
4719 }
4720
4721 var tabSize = cm.options.tabSize;
4722 var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
4723 if (line.stateAfter) line.stateAfter = null;
4724 var curSpaceString = line.text.match(/^\s*/)[0], indentation;
4725 if (!aggressive && !/\S/.test(line.text)) {
4726 indentation = 0;
4727 how = "not";
4728 } else if (how == "smart") {
4729 indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
4730 if (indentation == Pass || indentation > 150) {
4731 if (!aggressive) return;
4732 how = "prev";
4733 }
4734 }
4735 if (how == "prev") {
4736 if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
4737 else indentation = 0;
4738 } else if (how == "add") {
4739 indentation = curSpace + cm.options.indentUnit;
4740 } else if (how == "subtract") {
4741 indentation = curSpace - cm.options.indentUnit;
4742 } else if (typeof how == "number") {
4743 indentation = curSpace + how;
4744 }
4745 indentation = Math.max(0, indentation);
4746
4747 var indentString = "", pos = 0;
4748 if (cm.options.indentWithTabs)
4749 for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
4750 if (pos < indentation) indentString += spaceStr(indentation - pos);
4751
4752 if (indentString != curSpaceString) {
4753 replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
4754 line.stateAfter = null;
4755 return true;
4756 } else {
4757 // Ensure that, if the cursor was in the whitespace at the start
4758 // of the line, it is moved to the end of that space.
4759 for (var i = 0; i < doc.sel.ranges.length; i++) {
4760 var range = doc.sel.ranges[i];
4761 if (range.head.line == n && range.head.ch < curSpaceString.length) {
4762 var pos = Pos(n, curSpaceString.length);
4763 replaceOneSelection(doc, i, new Range(pos, pos));
4764 break;
4765 }
4766 }
4767 }
4768 }
4769
4770 // Utility for applying a change to a line by handle or number,
4771 // returning the number and optionally registering the line as
4772 // changed.
4773 function changeLine(doc, handle, changeType, op) {
4774 var no = handle, line = handle;
4775 if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
4776 else no = lineNo(handle);
4777 if (no == null) return null;
4778 if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
4779 return line;
4780 }
4781
4782 // Helper for deleting text near the selection(s), used to implement
4783 // backspace, delete, and similar functionality.
4784 function deleteNearSelection(cm, compute) {
4785 var ranges = cm.doc.sel.ranges, kill = [];
4786 // Build up a set of ranges to kill first, merging overlapping
4787 // ranges.
4788 for (var i = 0; i < ranges.length; i++) {
4789 var toKill = compute(ranges[i]);
4790 while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
4791 var replaced = kill.pop();
4792 if (cmp(replaced.from, toKill.from) < 0) {
4793 toKill.from = replaced.from;
4794 break;
4795 }
4796 }
4797 kill.push(toKill);
4798 }
4799 // Next, remove those actual ranges.
4800 runInOp(cm, function() {
4801 for (var i = kill.length - 1; i >= 0; i--)
4802 replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
4803 ensureCursorVisible(cm);
4804 });
4805 }
4806
4807 // Used for horizontal relative motion. Dir is -1 or 1 (left or
4808 // right), unit can be "char", "column" (like char, but doesn't
4809 // cross line boundaries), "word" (across next word), or "group" (to
4810 // the start of next group of word or non-word-non-whitespace
4811 // chars). The visually param controls whether, in right-to-left
4812 // text, direction 1 means to move towards the next index in the
4813 // string, or towards the character to the right of the current
4814 // position. The resulting position will have a hitSide=true
4815 // property if it reached the end of the document.
4816 function findPosH(doc, pos, dir, unit, visually) {
4817 var line = pos.line, ch = pos.ch, origDir = dir;
4818 var lineObj = getLine(doc, line);
4819 function findNextLine() {
4820 var l = line + dir;
4821 if (l < doc.first || l >= doc.first + doc.size) return false
4822 line = l;
4823 return lineObj = getLine(doc, l);
4824 }
4825 function moveOnce(boundToLine) {
4826 var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
4827 if (next == null) {
4828 if (!boundToLine && findNextLine()) {
4829 if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
4830 else ch = dir < 0 ? lineObj.text.length : 0;
4831 } else return false
4832 } else ch = next;
4833 return true;
4834 }
4835
4836 if (unit == "char") {
4837 moveOnce()
4838 } else if (unit == "column") {
4839 moveOnce(true)
4840 } else if (unit == "word" || unit == "group") {
4841 var sawType = null, group = unit == "group";
4842 var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
4843 for (var first = true;; first = false) {
4844 if (dir < 0 && !moveOnce(!first)) break;
4845 var cur = lineObj.text.charAt(ch) || "\n";
4846 var type = isWordChar(cur, helper) ? "w"
4847 : group && cur == "\n" ? "n"
4848 : !group || /\s/.test(cur) ? null
4849 : "p";
4850 if (group && !first && !type) type = "s";
4851 if (sawType && sawType != type) {
4852 if (dir < 0) {dir = 1; moveOnce();}
4853 break;
4854 }
4855
4856 if (type) sawType = type;
4857 if (dir > 0 && !moveOnce(!first)) break;
4858 }
4859 }
4860 var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true);
4861 if (!cmp(pos, result)) result.hitSide = true;
4862 return result;
4863 }
4864
4865 // For relative vertical movement. Dir may be -1 or 1. Unit can be
4866 // "page" or "line". The resulting position will have a hitSide=true
4867 // property if it reached the end of the document.
4868 function findPosV(cm, pos, dir, unit) {
4869 var doc = cm.doc, x = pos.left, y;
4870 if (unit == "page") {
4871 var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
4872 y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
4873 } else if (unit == "line") {
4874 y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
4875 }
4876 for (;;) {
4877 var target = coordsChar(cm, x, y);
4878 if (!target.outside) break;
4879 if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
4880 y += dir * 5;
4881 }
4882 return target;
4883 }
4884
4885 // EDITOR METHODS
4886
4887 // The publicly visible API. Note that methodOp(f) means
4888 // 'wrap f in an operation, performed on its `this` parameter'.
4889
4890 // This is not the complete set of editor methods. Most of the
4891 // methods defined on the Doc type are also injected into
4892 // CodeMirror.prototype, for backwards compatibility and
4893 // convenience.
4894
4895 CodeMirror.prototype = {
4896 constructor: CodeMirror,
4897 focus: function(){window.focus(); this.display.input.focus();},
4898
4899 setOption: function(option, value) {
4900 var options = this.options, old = options[option];
4901 if (options[option] == value && option != "mode") return;
4902 options[option] = value;
4903 if (optionHandlers.hasOwnProperty(option))
4904 operation(this, optionHandlers[option])(this, value, old);
4905 },
4906
4907 getOption: function(option) {return this.options[option];},
4908 getDoc: function() {return this.doc;},
4909
4910 addKeyMap: function(map, bottom) {
4911 this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
4912 },
4913 removeKeyMap: function(map) {
4914 var maps = this.state.keyMaps;
4915 for (var i = 0; i < maps.length; ++i)
4916 if (maps[i] == map || maps[i].name == map) {
4917 maps.splice(i, 1);
4918 return true;
4919 }
4920 },
4921
4922 addOverlay: methodOp(function(spec, options) {
4923 var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
4924 if (mode.startState) throw new Error("Overlays may not be stateful.");
4925 this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
4926 this.state.modeGen++;
4927 regChange(this);
4928 }),
4929 removeOverlay: methodOp(function(spec) {
4930 var overlays = this.state.overlays;
4931 for (var i = 0; i < overlays.length; ++i) {
4932 var cur = overlays[i].modeSpec;
4933 if (cur == spec || typeof spec == "string" && cur.name == spec) {
4934 overlays.splice(i, 1);
4935 this.state.modeGen++;
4936 regChange(this);
4937 return;
4938 }
4939 }
4940 }),
4941
4942 indentLine: methodOp(function(n, dir, aggressive) {
4943 if (typeof dir != "string" && typeof dir != "number") {
4944 if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
4945 else dir = dir ? "add" : "subtract";
4946 }
4947 if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
4948 }),
4949 indentSelection: methodOp(function(how) {
4950 var ranges = this.doc.sel.ranges, end = -1;
4951 for (var i = 0; i < ranges.length; i++) {
4952 var range = ranges[i];
4953 if (!range.empty()) {
4954 var from = range.from(), to = range.to();
4955 var start = Math.max(end, from.line);
4956 end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
4957 for (var j = start; j < end; ++j)
4958 indentLine(this, j, how);
4959 var newRanges = this.doc.sel.ranges;
4960 if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
4961 replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
4962 } else if (range.head.line > end) {
4963 indentLine(this, range.head.line, how, true);
4964 end = range.head.line;
4965 if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
4966 }
4967 }
4968 }),
4969
4970 // Fetch the parser token for a given character. Useful for hacks
4971 // that want to inspect the mode state (say, for completion).
4972 getTokenAt: function(pos, precise) {
4973 return takeToken(this, pos, precise);
4974 },
4975
4976 getLineTokens: function(line, precise) {
4977 return takeToken(this, Pos(line), precise, true);
4978 },
4979
4980 getTokenTypeAt: function(pos) {
4981 pos = clipPos(this.doc, pos);
4982 var styles = getLineStyles(this, getLine(this.doc, pos.line));
4983 var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
4984 var type;
4985 if (ch == 0) type = styles[2];
4986 else for (;;) {
4987 var mid = (before + after) >> 1;
4988 if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
4989 else if (styles[mid * 2 + 1] < ch) before = mid + 1;
4990 else { type = styles[mid * 2 + 2]; break; }
4991 }
4992 var cut = type ? type.indexOf("cm-overlay ") : -1;
4993 return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
4994 },
4995
4996 getModeAt: function(pos) {
4997 var mode = this.doc.mode;
4998 if (!mode.innerMode) return mode;
4999 return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
5000 },
5001
5002 getHelper: function(pos, type) {
5003 return this.getHelpers(pos, type)[0];
5004 },
5005
5006 getHelpers: function(pos, type) {
5007 var found = [];
5008 if (!helpers.hasOwnProperty(type)) return found;
5009 var help = helpers[type], mode = this.getModeAt(pos);
5010 if (typeof mode[type] == "string") {
5011 if (help[mode[type]]) found.push(help[mode[type]]);
5012 } else if (mode[type]) {
5013 for (var i = 0; i < mode[type].length; i++) {
5014 var val = help[mode[type][i]];
5015 if (val) found.push(val);
5016 }
5017 } else if (mode.helperType && help[mode.helperType]) {
5018 found.push(help[mode.helperType]);
5019 } else if (help[mode.name]) {
5020 found.push(help[mode.name]);
5021 }
5022 for (var i = 0; i < help._global.length; i++) {
5023 var cur = help._global[i];
5024 if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
5025 found.push(cur.val);
5026 }
5027 return found;
5028 },
5029
5030 getStateAfter: function(line, precise) {
5031 var doc = this.doc;
5032 line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
5033 return getStateBefore(this, line + 1, precise);
5034 },
5035
5036 cursorCoords: function(start, mode) {
5037 var pos, range = this.doc.sel.primary();
5038 if (start == null) pos = range.head;
5039 else if (typeof start == "object") pos = clipPos(this.doc, start);
5040 else pos = start ? range.from() : range.to();
5041 return cursorCoords(this, pos, mode || "page");
5042 },
5043
5044 charCoords: function(pos, mode) {
5045 return charCoords(this, clipPos(this.doc, pos), mode || "page");
5046 },
5047
5048 coordsChar: function(coords, mode) {
5049 coords = fromCoordSystem(this, coords, mode || "page");
5050 return coordsChar(this, coords.left, coords.top);
5051 },
5052
5053 lineAtHeight: function(height, mode) {
5054 height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
5055 return lineAtHeight(this.doc, height + this.display.viewOffset);
5056 },
5057 heightAtLine: function(line, mode) {
5058 var end = false, lineObj;
5059 if (typeof line == "number") {
5060 var last = this.doc.first + this.doc.size - 1;
5061 if (line < this.doc.first) line = this.doc.first;
5062 else if (line > last) { line = last; end = true; }
5063 lineObj = getLine(this.doc, line);
5064 } else {
5065 lineObj = line;
5066 }
5067 return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
5068 (end ? this.doc.height - heightAtLine(lineObj) : 0);
5069 },
5070
5071 defaultTextHeight: function() { return textHeight(this.display); },
5072 defaultCharWidth: function() { return charWidth(this.display); },
5073
5074 setGutterMarker: methodOp(function(line, gutterID, value) {
5075 return changeLine(this.doc, line, "gutter", function(line) {
5076 var markers = line.gutterMarkers || (line.gutterMarkers = {});
5077 markers[gutterID] = value;
5078 if (!value && isEmpty(markers)) line.gutterMarkers = null;
5079 return true;
5080 });
5081 }),
5082
5083 clearGutter: methodOp(function(gutterID) {
5084 var cm = this, doc = cm.doc, i = doc.first;
5085 doc.iter(function(line) {
5086 if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
5087 line.gutterMarkers[gutterID] = null;
5088 regLineChange(cm, i, "gutter");
5089 if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
5090 }
5091 ++i;
5092 });
5093 }),
5094
5095 lineInfo: function(line) {
5096 if (typeof line == "number") {
5097 if (!isLine(this.doc, line)) return null;
5098 var n = line;
5099 line = getLine(this.doc, line);
5100 if (!line) return null;
5101 } else {
5102 var n = lineNo(line);
5103 if (n == null) return null;
5104 }
5105 return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
5106 textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
5107 widgets: line.widgets};
5108 },
5109
5110 getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
5111
5112 addWidget: function(pos, node, scroll, vert, horiz) {
5113 var display = this.display;
5114 pos = cursorCoords(this, clipPos(this.doc, pos));
5115 var top = pos.bottom, left = pos.left;
5116 node.style.position = "absolute";
5117 node.setAttribute("cm-ignore-events", "true");
5118 this.display.input.setUneditable(node);
5119 display.sizer.appendChild(node);
5120 if (vert == "over") {
5121 top = pos.top;
5122 } else if (vert == "above" || vert == "near") {
5123 var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
5124 hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
5125 // Default to positioning above (if specified and possible); otherwise default to positioning below
5126 if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
5127 top = pos.top - node.offsetHeight;
5128 else if (pos.bottom + node.offsetHeight <= vspace)
5129 top = pos.bottom;
5130 if (left + node.offsetWidth > hspace)
5131 left = hspace - node.offsetWidth;
5132 }
5133 node.style.top = top + "px";
5134 node.style.left = node.style.right = "";
5135 if (horiz == "right") {
5136 left = display.sizer.clientWidth - node.offsetWidth;
5137 node.style.right = "0px";
5138 } else {
5139 if (horiz == "left") left = 0;
5140 else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
5141 node.style.left = left + "px";
5142 }
5143 if (scroll)
5144 scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
5145 },
5146
5147 triggerOnKeyDown: methodOp(onKeyDown),
5148 triggerOnKeyPress: methodOp(onKeyPress),
5149 triggerOnKeyUp: onKeyUp,
5150
5151 execCommand: function(cmd) {
5152 if (commands.hasOwnProperty(cmd))
5153 return commands[cmd].call(null, this);
5154 },
5155
5156 triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
5157
5158 findPosH: function(from, amount, unit, visually) {
5159 var dir = 1;
5160 if (amount < 0) { dir = -1; amount = -amount; }
5161 for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
5162 cur = findPosH(this.doc, cur, dir, unit, visually);
5163 if (cur.hitSide) break;
5164 }
5165 return cur;
5166 },
5167
5168 moveH: methodOp(function(dir, unit) {
5169 var cm = this;
5170 cm.extendSelectionsBy(function(range) {
5171 if (cm.display.shift || cm.doc.extend || range.empty())
5172 return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
5173 else
5174 return dir < 0 ? range.from() : range.to();
5175 }, sel_move);
5176 }),
5177
5178 deleteH: methodOp(function(dir, unit) {
5179 var sel = this.doc.sel, doc = this.doc;
5180 if (sel.somethingSelected())
5181 doc.replaceSelection("", null, "+delete");
5182 else
5183 deleteNearSelection(this, function(range) {
5184 var other = findPosH(doc, range.head, dir, unit, false);
5185 return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
5186 });
5187 }),
5188
5189 findPosV: function(from, amount, unit, goalColumn) {
5190 var dir = 1, x = goalColumn;
5191 if (amount < 0) { dir = -1; amount = -amount; }
5192 for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
5193 var coords = cursorCoords(this, cur, "div");
5194 if (x == null) x = coords.left;
5195 else coords.left = x;
5196 cur = findPosV(this, coords, dir, unit);
5197 if (cur.hitSide) break;
5198 }
5199 return cur;
5200 },
5201
5202 moveV: methodOp(function(dir, unit) {
5203 var cm = this, doc = this.doc, goals = [];
5204 var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
5205 doc.extendSelectionsBy(function(range) {
5206 if (collapse)
5207 return dir < 0 ? range.from() : range.to();
5208 var headPos = cursorCoords(cm, range.head, "div");
5209 if (range.goalColumn != null) headPos.left = range.goalColumn;
5210 goals.push(headPos.left);
5211 var pos = findPosV(cm, headPos, dir, unit);
5212 if (unit == "page" && range == doc.sel.primary())
5213 addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
5214 return pos;
5215 }, sel_move);
5216 if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
5217 doc.sel.ranges[i].goalColumn = goals[i];
5218 }),
5219
5220 // Find the word at the given position (as returned by coordsChar).
5221 findWordAt: function(pos) {
5222 var doc = this.doc, line = getLine(doc, pos.line).text;
5223 var start = pos.ch, end = pos.ch;
5224 if (line) {
5225 var helper = this.getHelper(pos, "wordChars");
5226 if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
5227 var startChar = line.charAt(start);
5228 var check = isWordChar(startChar, helper)
5229 ? function(ch) { return isWordChar(ch, helper); }
5230 : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
5231 : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
5232 while (start > 0 && check(line.charAt(start - 1))) --start;
5233 while (end < line.length && check(line.charAt(end))) ++end;
5234 }
5235 return new Range(Pos(pos.line, start), Pos(pos.line, end));
5236 },
5237
5238 toggleOverwrite: function(value) {
5239 if (value != null && value == this.state.overwrite) return;
5240 if (this.state.overwrite = !this.state.overwrite)
5241 addClass(this.display.cursorDiv, "CodeMirror-overwrite");
5242 else
5243 rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
5244
5245 signal(this, "overwriteToggle", this, this.state.overwrite);
5246 },
5247 hasFocus: function() { return this.display.input.getField() == activeElt(); },
5248 isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); },
5249
5250 scrollTo: methodOp(function(x, y) {
5251 if (x != null || y != null) resolveScrollToPos(this);
5252 if (x != null) this.curOp.scrollLeft = x;
5253 if (y != null) this.curOp.scrollTop = y;
5254 }),
5255 getScrollInfo: function() {
5256 var scroller = this.display.scroller;
5257 return {left: scroller.scrollLeft, top: scroller.scrollTop,
5258 height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
5259 width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
5260 clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
5261 },
5262
5263 scrollIntoView: methodOp(function(range, margin) {
5264 if (range == null) {
5265 range = {from: this.doc.sel.primary().head, to: null};
5266 if (margin == null) margin = this.options.cursorScrollMargin;
5267 } else if (typeof range == "number") {
5268 range = {from: Pos(range, 0), to: null};
5269 } else if (range.from == null) {
5270 range = {from: range, to: null};
5271 }
5272 if (!range.to) range.to = range.from;
5273 range.margin = margin || 0;
5274
5275 if (range.from.line != null) {
5276 resolveScrollToPos(this);
5277 this.curOp.scrollToPos = range;
5278 } else {
5279 var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
5280 Math.min(range.from.top, range.to.top) - range.margin,
5281 Math.max(range.from.right, range.to.right),
5282 Math.max(range.from.bottom, range.to.bottom) + range.margin);
5283 this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
5284 }
5285 }),
5286
5287 setSize: methodOp(function(width, height) {
5288 var cm = this;
5289 function interpret(val) {
5290 return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
5291 }
5292 if (width != null) cm.display.wrapper.style.width = interpret(width);
5293 if (height != null) cm.display.wrapper.style.height = interpret(height);
5294 if (cm.options.lineWrapping) clearLineMeasurementCache(this);
5295 var lineNo = cm.display.viewFrom;
5296 cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
5297 if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
5298 if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
5299 ++lineNo;
5300 });
5301 cm.curOp.forceUpdate = true;
5302 signal(cm, "refresh", this);
5303 }),
5304
5305 operation: function(f){return runInOp(this, f);},
5306
5307 refresh: methodOp(function() {
5308 var oldHeight = this.display.cachedTextHeight;
5309 regChange(this);
5310 this.curOp.forceUpdate = true;
5311 clearCaches(this);
5312 this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
5313 updateGutterSpace(this);
5314 if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
5315 estimateLineHeights(this);
5316 signal(this, "refresh", this);
5317 }),
5318
5319 swapDoc: methodOp(function(doc) {
5320 var old = this.doc;
5321 old.cm = null;
5322 attachDoc(this, doc);
5323 clearCaches(this);
5324 this.display.input.reset();
5325 this.scrollTo(doc.scrollLeft, doc.scrollTop);
5326 this.curOp.forceScroll = true;
5327 signalLater(this, "swapDoc", this, old);
5328 return old;
5329 }),
5330
5331 getInputField: function(){return this.display.input.getField();},
5332 getWrapperElement: function(){return this.display.wrapper;},
5333 getScrollerElement: function(){return this.display.scroller;},
5334 getGutterElement: function(){return this.display.gutters;}
5335 };
5336 eventMixin(CodeMirror);
5337
5338 // OPTION DEFAULTS
5339
5340 // The default configuration options.
5341 var defaults = CodeMirror.defaults = {};
5342 // Functions to run when options are changed.
5343 var optionHandlers = CodeMirror.optionHandlers = {};
5344
5345 function option(name, deflt, handle, notOnInit) {
5346 CodeMirror.defaults[name] = deflt;
5347 if (handle) optionHandlers[name] =
5348 notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
5349 }
5350
5351 // Passed to option handlers when there is no old value.
5352 var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
5353
5354 // These two are, on init, called from the constructor because they
5355 // have to be initialized before the editor can start at all.
5356 option("value", "", function(cm, val) {
5357 cm.setValue(val);
5358 }, true);
5359 option("mode", null, function(cm, val) {
5360 cm.doc.modeOption = val;
5361 loadMode(cm);
5362 }, true);
5363
5364 option("indentUnit", 2, loadMode, true);
5365 option("indentWithTabs", false);
5366 option("smartIndent", true);
5367 option("tabSize", 4, function(cm) {
5368 resetModeState(cm);
4690 resetModeState(cm);
5369 clearCaches(cm);
4691 }
5370 regChange(cm);
4692
5371 }, true);
4693 function resetModeState(cm) {
5372 option("lineSeparator", null, function(cm, val) {
5373 cm.doc.lineSep = val;
5374 if (!val) return;
5375 var newBreaks = [], lineNo = cm.doc.first;
5376 cm.doc.iter(function(line) {
4694 cm.doc.iter(function(line) {
5377 for (var pos = 0;;) {
4695 if (line.stateAfter) { line.stateAfter = null; }
5378 var found = line.text.indexOf(val, pos);
4696 if (line.styles) { line.styles = null; }
5379 if (found == -1) break;
5380 pos = found + val.length;
5381 newBreaks.push(Pos(lineNo, found));
5382 }
5383 lineNo++;
5384 });
5385 for (var i = newBreaks.length - 1; i >= 0; i--)
5386 replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length))
5387 });
5388 option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) {
5389 cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
5390 if (old != CodeMirror.Init) cm.refresh();
5391 });
5392 option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
5393 option("electricChars", true);
5394 option("inputStyle", mobile ? "contenteditable" : "textarea", function() {
5395 throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME
5396 }, true);
5397 option("rtlMoveVisually", !windows);
5398 option("wholeLineUpdateBefore", true);
5399
5400 option("theme", "default", function(cm) {
5401 themeChanged(cm);
5402 guttersChanged(cm);
5403 }, true);
5404 option("keyMap", "default", function(cm, val, old) {
5405 var next = getKeyMap(val);
5406 var prev = old != CodeMirror.Init && getKeyMap(old);
5407 if (prev && prev.detach) prev.detach(cm, next);
5408 if (next.attach) next.attach(cm, prev || null);
5409 });
5410 option("extraKeys", null);
5411
5412 option("lineWrapping", false, wrappingChanged, true);
5413 option("gutters", [], function(cm) {
5414 setGuttersForLineNumbers(cm.options);
5415 guttersChanged(cm);
5416 }, true);
5417 option("fixedGutter", true, function(cm, val) {
5418 cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
5419 cm.refresh();
5420 }, true);
5421 option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true);
5422 option("scrollbarStyle", "native", function(cm) {
5423 initScrollbars(cm);
5424 updateScrollbars(cm);
5425 cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
5426 cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
5427 }, true);
5428 option("lineNumbers", false, function(cm) {
5429 setGuttersForLineNumbers(cm.options);
5430 guttersChanged(cm);
5431 }, true);
5432 option("firstLineNumber", 1, guttersChanged, true);
5433 option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
5434 option("showCursorWhenSelecting", false, updateSelection, true);
5435
5436 option("resetSelectionOnContextMenu", true);
5437 option("lineWiseCopyCut", true);
5438
5439 option("readOnly", false, function(cm, val) {
5440 if (val == "nocursor") {
5441 onBlur(cm);
5442 cm.display.input.blur();
5443 cm.display.disabled = true;
5444 } else {
5445 cm.display.disabled = false;
5446 }
5447 cm.display.input.readOnlyChanged(val)
5448 });
5449 option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
5450 option("dragDrop", true, dragDropChanged);
5451 option("allowDropFileTypes", null);
5452
5453 option("cursorBlinkRate", 530);
5454 option("cursorScrollMargin", 0);
5455 option("cursorHeight", 1, updateSelection, true);
5456 option("singleCursorHeightPerLine", true, updateSelection, true);
5457 option("workTime", 100);
5458 option("workDelay", 100);
5459 option("flattenSpans", true, resetModeState, true);
5460 option("addModeClass", false, resetModeState, true);
5461 option("pollInterval", 100);
5462 option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
5463 option("historyEventDelay", 1250);
5464 option("viewportMargin", 10, function(cm){cm.refresh();}, true);
5465 option("maxHighlightLength", 10000, resetModeState, true);
5466 option("moveInputWithCursor", true, function(cm, val) {
5467 if (!val) cm.display.input.resetPosition();
5468 });
5469
5470 option("tabindex", null, function(cm, val) {
5471 cm.display.input.getField().tabIndex = val || "";
5472 });
5473 option("autofocus", null);
5474
5475 // MODE DEFINITION AND QUERYING
5476
5477 // Known modes, by name and by MIME
5478 var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
5479
5480 // Extra arguments are stored as the mode's dependencies, which is
5481 // used by (legacy) mechanisms like loadmode.js to automatically
5482 // load a mode. (Preferred mechanism is the require/define calls.)
5483 CodeMirror.defineMode = function(name, mode) {
5484 if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
5485 if (arguments.length > 2)
5486 mode.dependencies = Array.prototype.slice.call(arguments, 2);
5487 modes[name] = mode;
5488 };
5489
5490 CodeMirror.defineMIME = function(mime, spec) {
5491 mimeModes[mime] = spec;
5492 };
5493
5494 // Given a MIME type, a {name, ...options} config object, or a name
5495 // string, return a mode config object.
5496 CodeMirror.resolveMode = function(spec) {
5497 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
5498 spec = mimeModes[spec];
5499 } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
5500 var found = mimeModes[spec.name];
5501 if (typeof found == "string") found = {name: found};
5502 spec = createObj(found, spec);
5503 spec.name = found.name;
5504 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
5505 return CodeMirror.resolveMode("application/xml");
5506 }
5507 if (typeof spec == "string") return {name: spec};
5508 else return spec || {name: "null"};
5509 };
5510
5511 // Given a mode spec (anything that resolveMode accepts), find and
5512 // initialize an actual mode object.
5513 CodeMirror.getMode = function(options, spec) {
5514 var spec = CodeMirror.resolveMode(spec);
5515 var mfactory = modes[spec.name];
5516 if (!mfactory) return CodeMirror.getMode(options, "text/plain");
5517 var modeObj = mfactory(options, spec);
5518 if (modeExtensions.hasOwnProperty(spec.name)) {
5519 var exts = modeExtensions[spec.name];
5520 for (var prop in exts) {
5521 if (!exts.hasOwnProperty(prop)) continue;
5522 if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
5523 modeObj[prop] = exts[prop];
5524 }
5525 }
5526 modeObj.name = spec.name;
5527 if (spec.helperType) modeObj.helperType = spec.helperType;
5528 if (spec.modeProps) for (var prop in spec.modeProps)
5529 modeObj[prop] = spec.modeProps[prop];
5530
5531 return modeObj;
5532 };
5533
5534 // Minimal default mode.
5535 CodeMirror.defineMode("null", function() {
5536 return {token: function(stream) {stream.skipToEnd();}};
5537 });
5538 CodeMirror.defineMIME("text/plain", "null");
5539
5540 // This can be used to attach properties to mode objects from
5541 // outside the actual mode definition.
5542 var modeExtensions = CodeMirror.modeExtensions = {};
5543 CodeMirror.extendMode = function(mode, properties) {
5544 var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
5545 copyObj(properties, exts);
5546 };
5547
5548 // EXTENSIONS
5549
5550 CodeMirror.defineExtension = function(name, func) {
5551 CodeMirror.prototype[name] = func;
5552 };
5553 CodeMirror.defineDocExtension = function(name, func) {
5554 Doc.prototype[name] = func;
5555 };
5556 CodeMirror.defineOption = option;
5557
5558 var initHooks = [];
5559 CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
5560
5561 var helpers = CodeMirror.helpers = {};
5562 CodeMirror.registerHelper = function(type, name, value) {
5563 if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
5564 helpers[type][name] = value;
5565 };
5566 CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
5567 CodeMirror.registerHelper(type, name, value);
5568 helpers[type]._global.push({pred: predicate, val: value});
5569 };
5570
5571 // MODE STATE HANDLING
5572
5573 // Utility functions for working with state. Exported because nested
5574 // modes need to do this for their inner modes.
5575
5576 var copyState = CodeMirror.copyState = function(mode, state) {
5577 if (state === true) return state;
5578 if (mode.copyState) return mode.copyState(state);
5579 var nstate = {};
5580 for (var n in state) {
5581 var val = state[n];
5582 if (val instanceof Array) val = val.concat([]);
5583 nstate[n] = val;
5584 }
5585 return nstate;
5586 };
5587
5588 var startState = CodeMirror.startState = function(mode, a1, a2) {
5589 return mode.startState ? mode.startState(a1, a2) : true;
5590 };
5591
5592 // Given a mode and a state (for that mode), find the inner mode and
5593 // state at the position that the state refers to.
5594 CodeMirror.innerMode = function(mode, state) {
5595 while (mode.innerMode) {
5596 var info = mode.innerMode(state);
5597 if (!info || info.mode == mode) break;
5598 state = info.state;
5599 mode = info.mode;
5600 }
5601 return info || {mode: mode, state: state};
5602 };
5603
5604 // STANDARD COMMANDS
5605
5606 // Commands are parameter-less actions that can be performed on an
5607 // editor, mostly used for keybindings.
5608 var commands = CodeMirror.commands = {
5609 selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
5610 singleSelection: function(cm) {
5611 cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
5612 },
5613 killLine: function(cm) {
5614 deleteNearSelection(cm, function(range) {
5615 if (range.empty()) {
5616 var len = getLine(cm.doc, range.head.line).text.length;
5617 if (range.head.ch == len && range.head.line < cm.lastLine())
5618 return {from: range.head, to: Pos(range.head.line + 1, 0)};
5619 else
5620 return {from: range.head, to: Pos(range.head.line, len)};
5621 } else {
5622 return {from: range.from(), to: range.to()};
5623 }
5624 });
5625 },
5626 deleteLine: function(cm) {
5627 deleteNearSelection(cm, function(range) {
5628 return {from: Pos(range.from().line, 0),
5629 to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
5630 });
5631 },
5632 delLineLeft: function(cm) {
5633 deleteNearSelection(cm, function(range) {
5634 return {from: Pos(range.from().line, 0), to: range.from()};
5635 });
5636 },
5637 delWrappedLineLeft: function(cm) {
5638 deleteNearSelection(cm, function(range) {
5639 var top = cm.charCoords(range.head, "div").top + 5;
5640 var leftPos = cm.coordsChar({left: 0, top: top}, "div");
5641 return {from: leftPos, to: range.from()};
5642 });
5643 },
5644 delWrappedLineRight: function(cm) {
5645 deleteNearSelection(cm, function(range) {
5646 var top = cm.charCoords(range.head, "div").top + 5;
5647 var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
5648 return {from: range.from(), to: rightPos };
5649 });
4697 });
5650 },
4698 cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
5651 undo: function(cm) {cm.undo();},
4699 startWorker(cm, 100);
5652 redo: function(cm) {cm.redo();},
4700 cm.state.modeGen++;
5653 undoSelection: function(cm) {cm.undoSelection();},
4701 if (cm.curOp) { regChange(cm); }
5654 redoSelection: function(cm) {cm.redoSelection();},
5655 goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
5656 goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
5657 goLineStart: function(cm) {
5658 cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
5659 {origin: "+move", bias: 1});
5660 },
5661 goLineStartSmart: function(cm) {
5662 cm.extendSelectionsBy(function(range) {
5663 return lineStartSmart(cm, range.head);
5664 }, {origin: "+move", bias: 1});
5665 },
5666 goLineEnd: function(cm) {
5667 cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
5668 {origin: "+move", bias: -1});
5669 },
5670 goLineRight: function(cm) {
5671 cm.extendSelectionsBy(function(range) {
5672 var top = cm.charCoords(range.head, "div").top + 5;
5673 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
5674 }, sel_move);
5675 },
5676 goLineLeft: function(cm) {
5677 cm.extendSelectionsBy(function(range) {
5678 var top = cm.charCoords(range.head, "div").top + 5;
5679 return cm.coordsChar({left: 0, top: top}, "div");
5680 }, sel_move);
5681 },
5682 goLineLeftSmart: function(cm) {
5683 cm.extendSelectionsBy(function(range) {
5684 var top = cm.charCoords(range.head, "div").top + 5;
5685 var pos = cm.coordsChar({left: 0, top: top}, "div");
5686 if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
5687 return pos;
5688 }, sel_move);
5689 },
5690 goLineUp: function(cm) {cm.moveV(-1, "line");},
5691 goLineDown: function(cm) {cm.moveV(1, "line");},
5692 goPageUp: function(cm) {cm.moveV(-1, "page");},
5693 goPageDown: function(cm) {cm.moveV(1, "page");},
5694 goCharLeft: function(cm) {cm.moveH(-1, "char");},
5695 goCharRight: function(cm) {cm.moveH(1, "char");},
5696 goColumnLeft: function(cm) {cm.moveH(-1, "column");},
5697 goColumnRight: function(cm) {cm.moveH(1, "column");},
5698 goWordLeft: function(cm) {cm.moveH(-1, "word");},
5699 goGroupRight: function(cm) {cm.moveH(1, "group");},
5700 goGroupLeft: function(cm) {cm.moveH(-1, "group");},
5701 goWordRight: function(cm) {cm.moveH(1, "word");},
5702 delCharBefore: function(cm) {cm.deleteH(-1, "char");},
5703 delCharAfter: function(cm) {cm.deleteH(1, "char");},
5704 delWordBefore: function(cm) {cm.deleteH(-1, "word");},
5705 delWordAfter: function(cm) {cm.deleteH(1, "word");},
5706 delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
5707 delGroupAfter: function(cm) {cm.deleteH(1, "group");},
5708 indentAuto: function(cm) {cm.indentSelection("smart");},
5709 indentMore: function(cm) {cm.indentSelection("add");},
5710 indentLess: function(cm) {cm.indentSelection("subtract");},
5711 insertTab: function(cm) {cm.replaceSelection("\t");},
5712 insertSoftTab: function(cm) {
5713 var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
5714 for (var i = 0; i < ranges.length; i++) {
5715 var pos = ranges[i].from();
5716 var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
5717 spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
5718 }
5719 cm.replaceSelections(spaces);
5720 },
5721 defaultTab: function(cm) {
5722 if (cm.somethingSelected()) cm.indentSelection("add");
5723 else cm.execCommand("insertTab");
5724 },
5725 transposeChars: function(cm) {
5726 runInOp(cm, function() {
5727 var ranges = cm.listSelections(), newSel = [];
5728 for (var i = 0; i < ranges.length; i++) {
5729 var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
5730 if (line) {
5731 if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
5732 if (cur.ch > 0) {
5733 cur = new Pos(cur.line, cur.ch + 1);
5734 cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
5735 Pos(cur.line, cur.ch - 2), cur, "+transpose");
5736 } else if (cur.line > cm.doc.first) {
5737 var prev = getLine(cm.doc, cur.line - 1).text;
5738 if (prev)
5739 cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
5740 prev.charAt(prev.length - 1),
5741 Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
5742 }
5743 }
5744 newSel.push(new Range(cur, cur));
5745 }
5746 cm.setSelections(newSel);
5747 });
5748 },
5749 newlineAndIndent: function(cm) {
5750 runInOp(cm, function() {
5751 var len = cm.listSelections().length;
5752 for (var i = 0; i < len; i++) {
5753 var range = cm.listSelections()[i];
5754 cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
5755 cm.indentLine(range.from().line + 1, null, true);
5756 }
5757 ensureCursorVisible(cm);
5758 });
5759 },
5760 toggleOverwrite: function(cm) {cm.toggleOverwrite();}
5761 };
5762
5763
5764 // STANDARD KEYMAPS
5765
5766 var keyMap = CodeMirror.keyMap = {};
5767
5768 keyMap.basic = {
5769 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
5770 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
5771 "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
5772 "Tab": "defaultTab", "Shift-Tab": "indentAuto",
5773 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
5774 "Esc": "singleSelection"
5775 };
5776 // Note that the save and find-related commands aren't defined by
5777 // default. User code or addons can define them. Unknown commands
5778 // are simply ignored.
5779 keyMap.pcDefault = {
5780 "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
5781 "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
5782 "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
5783 "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
5784 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
5785 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
5786 "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
5787 fallthrough: "basic"
5788 };
5789 // Very basic readline/emacs-style bindings, which are standard on Mac.
5790 keyMap.emacsy = {
5791 "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
5792 "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
5793 "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
5794 "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
5795 };
5796 keyMap.macDefault = {
5797 "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
5798 "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
5799 "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
5800 "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
5801 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
5802 "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
5803 "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
5804 fallthrough: ["basic", "emacsy"]
5805 };
5806 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
5807
5808 // KEYMAP DISPATCH
5809
5810 function normalizeKeyName(name) {
5811 var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
5812 var alt, ctrl, shift, cmd;
5813 for (var i = 0; i < parts.length - 1; i++) {
5814 var mod = parts[i];
5815 if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
5816 else if (/^a(lt)?$/i.test(mod)) alt = true;
5817 else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
5818 else if (/^s(hift)$/i.test(mod)) shift = true;
5819 else throw new Error("Unrecognized modifier name: " + mod);
5820 }
5821 if (alt) name = "Alt-" + name;
5822 if (ctrl) name = "Ctrl-" + name;
5823 if (cmd) name = "Cmd-" + name;
5824 if (shift) name = "Shift-" + name;
5825 return name;
5826 }
5827
5828 // This is a kludge to keep keymaps mostly working as raw objects
5829 // (backwards compatibility) while at the same time support features
5830 // like normalization and multi-stroke key bindings. It compiles a
5831 // new normalized keymap, and then updates the old object to reflect
5832 // this.
5833 CodeMirror.normalizeKeyMap = function(keymap) {
5834 var copy = {};
5835 for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
5836 var value = keymap[keyname];
5837 if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
5838 if (value == "...") { delete keymap[keyname]; continue; }
5839
5840 var keys = map(keyname.split(" "), normalizeKeyName);
5841 for (var i = 0; i < keys.length; i++) {
5842 var val, name;
5843 if (i == keys.length - 1) {
5844 name = keys.join(" ");
5845 val = value;
5846 } else {
5847 name = keys.slice(0, i + 1).join(" ");
5848 val = "...";
5849 }
5850 var prev = copy[name];
5851 if (!prev) copy[name] = val;
5852 else if (prev != val) throw new Error("Inconsistent bindings for " + name);
5853 }
5854 delete keymap[keyname];
5855 }
5856 for (var prop in copy) keymap[prop] = copy[prop];
5857 return keymap;
5858 };
5859
5860 var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
5861 map = getKeyMap(map);
5862 var found = map.call ? map.call(key, context) : map[key];
5863 if (found === false) return "nothing";
5864 if (found === "...") return "multi";
5865 if (found != null && handle(found)) return "handled";
5866
5867 if (map.fallthrough) {
5868 if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
5869 return lookupKey(key, map.fallthrough, handle, context);
5870 for (var i = 0; i < map.fallthrough.length; i++) {
5871 var result = lookupKey(key, map.fallthrough[i], handle, context);
5872 if (result) return result;
5873 }
5874 }
5875 };
5876
5877 // Modifier key presses don't count as 'real' key presses for the
5878 // purpose of keymap fallthrough.
5879 var isModifierKey = CodeMirror.isModifierKey = function(value) {
5880 var name = typeof value == "string" ? value : keyNames[value.keyCode];
5881 return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
5882 };
5883
5884 // Look up the name of a key as indicated by an event object.
5885 var keyName = CodeMirror.keyName = function(event, noShift) {
5886 if (presto && event.keyCode == 34 && event["char"]) return false;
5887 var base = keyNames[event.keyCode], name = base;
5888 if (name == null || event.altGraphKey) return false;
5889 if (event.altKey && base != "Alt") name = "Alt-" + name;
5890 if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name;
5891 if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name;
5892 if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name;
5893 return name;
5894 };
5895
5896 function getKeyMap(val) {
5897 return typeof val == "string" ? keyMap[val] : val;
5898 }
5899
5900 // FROMTEXTAREA
5901
5902 CodeMirror.fromTextArea = function(textarea, options) {
5903 options = options ? copyObj(options) : {};
5904 options.value = textarea.value;
5905 if (!options.tabindex && textarea.tabIndex)
5906 options.tabindex = textarea.tabIndex;
5907 if (!options.placeholder && textarea.placeholder)
5908 options.placeholder = textarea.placeholder;
5909 // Set autofocus to true if this textarea is focused, or if it has
5910 // autofocus and no other element is focused.
5911 if (options.autofocus == null) {
5912 var hasFocus = activeElt();
5913 options.autofocus = hasFocus == textarea ||
5914 textarea.getAttribute("autofocus") != null && hasFocus == document.body;
5915 }
5916
5917 function save() {textarea.value = cm.getValue();}
5918 if (textarea.form) {
5919 on(textarea.form, "submit", save);
5920 // Deplorable hack to make the submit method do the right thing.
5921 if (!options.leaveSubmitMethodAlone) {
5922 var form = textarea.form, realSubmit = form.submit;
5923 try {
5924 var wrappedSubmit = form.submit = function() {
5925 save();
5926 form.submit = realSubmit;
5927 form.submit();
5928 form.submit = wrappedSubmit;
5929 };
5930 } catch(e) {}
5931 }
5932 }
5933
5934 options.finishInit = function(cm) {
5935 cm.save = save;
5936 cm.getTextArea = function() { return textarea; };
5937 cm.toTextArea = function() {
5938 cm.toTextArea = isNaN; // Prevent this from being ran twice
5939 save();
5940 textarea.parentNode.removeChild(cm.getWrapperElement());
5941 textarea.style.display = "";
5942 if (textarea.form) {
5943 off(textarea.form, "submit", save);
5944 if (typeof textarea.form.submit == "function")
5945 textarea.form.submit = realSubmit;
5946 }
5947 };
5948 };
5949
5950 textarea.style.display = "none";
5951 var cm = CodeMirror(function(node) {
5952 textarea.parentNode.insertBefore(node, textarea.nextSibling);
5953 }, options);
5954 return cm;
5955 };
5956
5957 // STRING STREAM
5958
5959 // Fed to the mode parsers, provides helper functions to make
5960 // parsers more succinct.
5961
5962 var StringStream = CodeMirror.StringStream = function(string, tabSize) {
5963 this.pos = this.start = 0;
5964 this.string = string;
5965 this.tabSize = tabSize || 8;
5966 this.lastColumnPos = this.lastColumnValue = 0;
5967 this.lineStart = 0;
5968 };
5969
5970 StringStream.prototype = {
5971 eol: function() {return this.pos >= this.string.length;},
5972 sol: function() {return this.pos == this.lineStart;},
5973 peek: function() {return this.string.charAt(this.pos) || undefined;},
5974 next: function() {
5975 if (this.pos < this.string.length)
5976 return this.string.charAt(this.pos++);
5977 },
5978 eat: function(match) {
5979 var ch = this.string.charAt(this.pos);
5980 if (typeof match == "string") var ok = ch == match;
5981 else var ok = ch && (match.test ? match.test(ch) : match(ch));
5982 if (ok) {++this.pos; return ch;}
5983 },
5984 eatWhile: function(match) {
5985 var start = this.pos;
5986 while (this.eat(match)){}
5987 return this.pos > start;
5988 },
5989 eatSpace: function() {
5990 var start = this.pos;
5991 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
5992 return this.pos > start;
5993 },
5994 skipToEnd: function() {this.pos = this.string.length;},
5995 skipTo: function(ch) {
5996 var found = this.string.indexOf(ch, this.pos);
5997 if (found > -1) {this.pos = found; return true;}
5998 },
5999 backUp: function(n) {this.pos -= n;},
6000 column: function() {
6001 if (this.lastColumnPos < this.start) {
6002 this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
6003 this.lastColumnPos = this.start;
6004 }
6005 return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
6006 },
6007 indentation: function() {
6008 return countColumn(this.string, null, this.tabSize) -
6009 (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
6010 },
6011 match: function(pattern, consume, caseInsensitive) {
6012 if (typeof pattern == "string") {
6013 var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
6014 var substr = this.string.substr(this.pos, pattern.length);
6015 if (cased(substr) == cased(pattern)) {
6016 if (consume !== false) this.pos += pattern.length;
6017 return true;
6018 }
6019 } else {
6020 var match = this.string.slice(this.pos).match(pattern);
6021 if (match && match.index > 0) return null;
6022 if (match && consume !== false) this.pos += match[0].length;
6023 return match;
6024 }
6025 },
6026 current: function(){return this.string.slice(this.start, this.pos);},
6027 hideFirstChars: function(n, inner) {
6028 this.lineStart += n;
6029 try { return inner(); }
6030 finally { this.lineStart -= n; }
6031 }
6032 };
6033
6034 // TEXTMARKERS
6035
6036 // Created with markText and setBookmark methods. A TextMarker is a
6037 // handle that can be used to clear or find a marked position in the
6038 // document. Line objects hold arrays (markedSpans) containing
6039 // {from, to, marker} object pointing to such marker objects, and
6040 // indicating that such a marker is present on that line. Multiple
6041 // lines may point to the same marker when it spans across lines.
6042 // The spans will have null for their from/to properties when the
6043 // marker continues beyond the start/end of the line. Markers have
6044 // links back to the lines they currently touch.
6045
6046 var nextMarkerId = 0;
6047
6048 var TextMarker = CodeMirror.TextMarker = function(doc, type) {
6049 this.lines = [];
6050 this.type = type;
6051 this.doc = doc;
6052 this.id = ++nextMarkerId;
6053 };
6054 eventMixin(TextMarker);
6055
6056 // Clear the marker.
6057 TextMarker.prototype.clear = function() {
6058 if (this.explicitlyCleared) return;
6059 var cm = this.doc.cm, withOp = cm && !cm.curOp;
6060 if (withOp) startOperation(cm);
6061 if (hasHandler(this, "clear")) {
6062 var found = this.find();
6063 if (found) signalLater(this, "clear", found.from, found.to);
6064 }
6065 var min = null, max = null;
6066 for (var i = 0; i < this.lines.length; ++i) {
6067 var line = this.lines[i];
6068 var span = getMarkedSpanFor(line.markedSpans, this);
6069 if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
6070 else if (cm) {
6071 if (span.to != null) max = lineNo(line);
6072 if (span.from != null) min = lineNo(line);
6073 }
6074 line.markedSpans = removeMarkedSpan(line.markedSpans, span);
6075 if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
6076 updateLineHeight(line, textHeight(cm.display));
6077 }
6078 if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
6079 var visual = visualLine(this.lines[i]), len = lineLength(visual);
6080 if (len > cm.display.maxLineLength) {
6081 cm.display.maxLine = visual;
6082 cm.display.maxLineLength = len;
6083 cm.display.maxLineChanged = true;
6084 }
6085 }
6086
6087 if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
6088 this.lines.length = 0;
6089 this.explicitlyCleared = true;
6090 if (this.atomic && this.doc.cantEdit) {
6091 this.doc.cantEdit = false;
6092 if (cm) reCheckSelection(cm.doc);
6093 }
6094 if (cm) signalLater(cm, "markerCleared", cm, this);
6095 if (withOp) endOperation(cm);
6096 if (this.parent) this.parent.clear();
6097 };
6098
6099 // Find the position of the marker in the document. Returns a {from,
6100 // to} object by default. Side can be passed to get a specific side
6101 // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
6102 // Pos objects returned contain a line object, rather than a line
6103 // number (used to prevent looking up the same line twice).
6104 TextMarker.prototype.find = function(side, lineObj) {
6105 if (side == null && this.type == "bookmark") side = 1;
6106 var from, to;
6107 for (var i = 0; i < this.lines.length; ++i) {
6108 var line = this.lines[i];
6109 var span = getMarkedSpanFor(line.markedSpans, this);
6110 if (span.from != null) {
6111 from = Pos(lineObj ? line : lineNo(line), span.from);
6112 if (side == -1) return from;
6113 }
6114 if (span.to != null) {
6115 to = Pos(lineObj ? line : lineNo(line), span.to);
6116 if (side == 1) return to;
6117 }
6118 }
6119 return from && {from: from, to: to};
6120 };
6121
6122 // Signals that the marker's widget changed, and surrounding layout
6123 // should be recomputed.
6124 TextMarker.prototype.changed = function() {
6125 var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
6126 if (!pos || !cm) return;
6127 runInOp(cm, function() {
6128 var line = pos.line, lineN = lineNo(pos.line);
6129 var view = findViewForLine(cm, lineN);
6130 if (view) {
6131 clearLineMeasurementCacheFor(view);
6132 cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
6133 }
6134 cm.curOp.updateMaxLine = true;
6135 if (!lineIsHidden(widget.doc, line) && widget.height != null) {
6136 var oldHeight = widget.height;
6137 widget.height = null;
6138 var dHeight = widgetHeight(widget) - oldHeight;
6139 if (dHeight)
6140 updateLineHeight(line, line.height + dHeight);
6141 }
6142 });
6143 };
6144
6145 TextMarker.prototype.attachLine = function(line) {
6146 if (!this.lines.length && this.doc.cm) {
6147 var op = this.doc.cm.curOp;
6148 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
6149 (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
6150 }
6151 this.lines.push(line);
6152 };
6153 TextMarker.prototype.detachLine = function(line) {
6154 this.lines.splice(indexOf(this.lines, line), 1);
6155 if (!this.lines.length && this.doc.cm) {
6156 var op = this.doc.cm.curOp;
6157 (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
6158 }
6159 };
6160
6161 // Collapsed markers have unique ids, in order to be able to order
6162 // them, which is needed for uniquely determining an outer marker
6163 // when they overlap (they may nest, but not partially overlap).
6164 var nextMarkerId = 0;
6165
6166 // Create a marker, wire it up to the right lines, and
6167 function markText(doc, from, to, options, type) {
6168 // Shared markers (across linked documents) are handled separately
6169 // (markTextShared will call out to this again, once per
6170 // document).
6171 if (options && options.shared) return markTextShared(doc, from, to, options, type);
6172 // Ensure we are in an operation.
6173 if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
6174
6175 var marker = new TextMarker(doc, type), diff = cmp(from, to);
6176 if (options) copyObj(options, marker, false);
6177 // Don't connect empty markers unless clearWhenEmpty is false
6178 if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
6179 return marker;
6180 if (marker.replacedWith) {
6181 // Showing up as a widget implies collapsed (widget replaces text)
6182 marker.collapsed = true;
6183 marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
6184 if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
6185 if (options.insertLeft) marker.widgetNode.insertLeft = true;
6186 }
6187 if (marker.collapsed) {
6188 if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
6189 from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
6190 throw new Error("Inserting collapsed marker partially overlapping an existing one");
6191 sawCollapsedSpans = true;
6192 }
6193
6194 if (marker.addToHistory)
6195 addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
6196
6197 var curLine = from.line, cm = doc.cm, updateMaxLine;
6198 doc.iter(curLine, to.line + 1, function(line) {
6199 if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
6200 updateMaxLine = true;
6201 if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
6202 addMarkedSpan(line, new MarkedSpan(marker,
6203 curLine == from.line ? from.ch : null,
6204 curLine == to.line ? to.ch : null));
6205 ++curLine;
6206 });
6207 // lineIsHidden depends on the presence of the spans, so needs a second pass
6208 if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
6209 if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
6210 });
6211
6212 if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
6213
6214 if (marker.readOnly) {
6215 sawReadOnlySpans = true;
6216 if (doc.history.done.length || doc.history.undone.length)
6217 doc.clearHistory();
6218 }
6219 if (marker.collapsed) {
6220 marker.id = ++nextMarkerId;
6221 marker.atomic = true;
6222 }
6223 if (cm) {
6224 // Sync editor state
6225 if (updateMaxLine) cm.curOp.updateMaxLine = true;
6226 if (marker.collapsed)
6227 regChange(cm, from.line, to.line + 1);
6228 else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
6229 for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
6230 if (marker.atomic) reCheckSelection(cm.doc);
6231 signalLater(cm, "markerAdded", cm, marker);
6232 }
6233 return marker;
6234 }
6235
6236 // SHARED TEXTMARKERS
6237
6238 // A shared marker spans multiple linked documents. It is
6239 // implemented as a meta-marker-object controlling multiple normal
6240 // markers.
6241 var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
6242 this.markers = markers;
6243 this.primary = primary;
6244 for (var i = 0; i < markers.length; ++i)
6245 markers[i].parent = this;
6246 };
6247 eventMixin(SharedTextMarker);
6248
6249 SharedTextMarker.prototype.clear = function() {
6250 if (this.explicitlyCleared) return;
6251 this.explicitlyCleared = true;
6252 for (var i = 0; i < this.markers.length; ++i)
6253 this.markers[i].clear();
6254 signalLater(this, "clear");
6255 };
6256 SharedTextMarker.prototype.find = function(side, lineObj) {
6257 return this.primary.find(side, lineObj);
6258 };
6259
6260 function markTextShared(doc, from, to, options, type) {
6261 options = copyObj(options);
6262 options.shared = false;
6263 var markers = [markText(doc, from, to, options, type)], primary = markers[0];
6264 var widget = options.widgetNode;
6265 linkedDocs(doc, function(doc) {
6266 if (widget) options.widgetNode = widget.cloneNode(true);
6267 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
6268 for (var i = 0; i < doc.linked.length; ++i)
6269 if (doc.linked[i].isParent) return;
6270 primary = lst(markers);
6271 });
6272 return new SharedTextMarker(markers, primary);
6273 }
6274
6275 function findSharedMarkers(doc) {
6276 return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
6277 function(m) { return m.parent; });
6278 }
6279
6280 function copySharedMarkers(doc, markers) {
6281 for (var i = 0; i < markers.length; i++) {
6282 var marker = markers[i], pos = marker.find();
6283 var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
6284 if (cmp(mFrom, mTo)) {
6285 var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
6286 marker.markers.push(subMark);
6287 subMark.parent = marker;
6288 }
6289 }
6290 }
6291
6292 function detachSharedMarkers(markers) {
6293 for (var i = 0; i < markers.length; i++) {
6294 var marker = markers[i], linked = [marker.primary.doc];;
6295 linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
6296 for (var j = 0; j < marker.markers.length; j++) {
6297 var subMarker = marker.markers[j];
6298 if (indexOf(linked, subMarker.doc) == -1) {
6299 subMarker.parent = null;
6300 marker.markers.splice(j--, 1);
6301 }
6302 }
6303 }
6304 }
6305
6306 // TEXTMARKER SPANS
6307
6308 function MarkedSpan(marker, from, to) {
6309 this.marker = marker;
6310 this.from = from; this.to = to;
6311 }
6312
6313 // Search an array of spans for a span matching the given marker.
6314 function getMarkedSpanFor(spans, marker) {
6315 if (spans) for (var i = 0; i < spans.length; ++i) {
6316 var span = spans[i];
6317 if (span.marker == marker) return span;
6318 }
6319 }
6320 // Remove a span from an array, returning undefined if no spans are
6321 // left (we don't store arrays for lines without spans).
6322 function removeMarkedSpan(spans, span) {
6323 for (var r, i = 0; i < spans.length; ++i)
6324 if (spans[i] != span) (r || (r = [])).push(spans[i]);
6325 return r;
6326 }
6327 // Add a span to a line.
6328 function addMarkedSpan(line, span) {
6329 line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
6330 span.marker.attachLine(line);
6331 }
6332
6333 // Used for the algorithm that adjusts markers for a change in the
6334 // document. These functions cut an array of spans at a given
6335 // character position, returning an array of remaining chunks (or
6336 // undefined if nothing remains).
6337 function markedSpansBefore(old, startCh, isInsert) {
6338 if (old) for (var i = 0, nw; i < old.length; ++i) {
6339 var span = old[i], marker = span.marker;
6340 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
6341 if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
6342 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
6343 (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
6344 }
6345 }
6346 return nw;
6347 }
6348 function markedSpansAfter(old, endCh, isInsert) {
6349 if (old) for (var i = 0, nw; i < old.length; ++i) {
6350 var span = old[i], marker = span.marker;
6351 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
6352 if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
6353 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
6354 (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
6355 span.to == null ? null : span.to - endCh));
6356 }
6357 }
6358 return nw;
6359 }
6360
6361 // Given a change object, compute the new set of marker spans that
6362 // cover the line in which the change took place. Removes spans
6363 // entirely within the change, reconnects spans belonging to the
6364 // same marker that appear on both sides of the change, and cuts off
6365 // spans partially within the change. Returns an array of span
6366 // arrays with one element for each line in (after) the change.
6367 function stretchSpansOverChange(doc, change) {
6368 if (change.full) return null;
6369 var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
6370 var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
6371 if (!oldFirst && !oldLast) return null;
6372
6373 var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
6374 // Get the spans that 'stick out' on both sides
6375 var first = markedSpansBefore(oldFirst, startCh, isInsert);
6376 var last = markedSpansAfter(oldLast, endCh, isInsert);
6377
6378 // Next, merge those two ends
6379 var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
6380 if (first) {
6381 // Fix up .to properties of first
6382 for (var i = 0; i < first.length; ++i) {
6383 var span = first[i];
6384 if (span.to == null) {
6385 var found = getMarkedSpanFor(last, span.marker);
6386 if (!found) span.to = startCh;
6387 else if (sameLine) span.to = found.to == null ? null : found.to + offset;
6388 }
6389 }
6390 }
6391 if (last) {
6392 // Fix up .from in last (or move them into first in case of sameLine)
6393 for (var i = 0; i < last.length; ++i) {
6394 var span = last[i];
6395 if (span.to != null) span.to += offset;
6396 if (span.from == null) {
6397 var found = getMarkedSpanFor(first, span.marker);
6398 if (!found) {
6399 span.from = offset;
6400 if (sameLine) (first || (first = [])).push(span);
6401 }
6402 } else {
6403 span.from += offset;
6404 if (sameLine) (first || (first = [])).push(span);
6405 }
6406 }
6407 }
6408 // Make sure we didn't create any zero-length spans
6409 if (first) first = clearEmptySpans(first);
6410 if (last && last != first) last = clearEmptySpans(last);
6411
6412 var newMarkers = [first];
6413 if (!sameLine) {
6414 // Fill gap with whole-line-spans
6415 var gap = change.text.length - 2, gapMarkers;
6416 if (gap > 0 && first)
6417 for (var i = 0; i < first.length; ++i)
6418 if (first[i].to == null)
6419 (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
6420 for (var i = 0; i < gap; ++i)
6421 newMarkers.push(gapMarkers);
6422 newMarkers.push(last);
6423 }
6424 return newMarkers;
6425 }
6426
6427 // Remove spans that are empty and don't have a clearWhenEmpty
6428 // option of false.
6429 function clearEmptySpans(spans) {
6430 for (var i = 0; i < spans.length; ++i) {
6431 var span = spans[i];
6432 if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
6433 spans.splice(i--, 1);
6434 }
6435 if (!spans.length) return null;
6436 return spans;
6437 }
6438
6439 // Used for un/re-doing changes from the history. Combines the
6440 // result of computing the existing spans with the set of spans that
6441 // existed in the history (so that deleting around a span and then
6442 // undoing brings back the span).
6443 function mergeOldSpans(doc, change) {
6444 var old = getOldSpans(doc, change);
6445 var stretched = stretchSpansOverChange(doc, change);
6446 if (!old) return stretched;
6447 if (!stretched) return old;
6448
6449 for (var i = 0; i < old.length; ++i) {
6450 var oldCur = old[i], stretchCur = stretched[i];
6451 if (oldCur && stretchCur) {
6452 spans: for (var j = 0; j < stretchCur.length; ++j) {
6453 var span = stretchCur[j];
6454 for (var k = 0; k < oldCur.length; ++k)
6455 if (oldCur[k].marker == span.marker) continue spans;
6456 oldCur.push(span);
6457 }
6458 } else if (stretchCur) {
6459 old[i] = stretchCur;
6460 }
6461 }
6462 return old;
6463 }
6464
6465 // Used to 'clip' out readOnly ranges when making a change.
6466 function removeReadOnlyRanges(doc, from, to) {
6467 var markers = null;
6468 doc.iter(from.line, to.line + 1, function(line) {
6469 if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
6470 var mark = line.markedSpans[i].marker;
6471 if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
6472 (markers || (markers = [])).push(mark);
6473 }
6474 });
6475 if (!markers) return null;
6476 var parts = [{from: from, to: to}];
6477 for (var i = 0; i < markers.length; ++i) {
6478 var mk = markers[i], m = mk.find(0);
6479 for (var j = 0; j < parts.length; ++j) {
6480 var p = parts[j];
6481 if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
6482 var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
6483 if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
6484 newParts.push({from: p.from, to: m.from});
6485 if (dto > 0 || !mk.inclusiveRight && !dto)
6486 newParts.push({from: m.to, to: p.to});
6487 parts.splice.apply(parts, newParts);
6488 j += newParts.length - 1;
6489 }
6490 }
6491 return parts;
6492 }
6493
6494 // Connect or disconnect spans from a line.
6495 function detachMarkedSpans(line) {
6496 var spans = line.markedSpans;
6497 if (!spans) return;
6498 for (var i = 0; i < spans.length; ++i)
6499 spans[i].marker.detachLine(line);
6500 line.markedSpans = null;
6501 }
6502 function attachMarkedSpans(line, spans) {
6503 if (!spans) return;
6504 for (var i = 0; i < spans.length; ++i)
6505 spans[i].marker.attachLine(line);
6506 line.markedSpans = spans;
6507 }
6508
6509 // Helpers used when computing which overlapping collapsed span
6510 // counts as the larger one.
6511 function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
6512 function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
6513
6514 // Returns a number indicating which of two overlapping collapsed
6515 // spans is larger (and thus includes the other). Falls back to
6516 // comparing ids when the spans cover exactly the same range.
6517 function compareCollapsedMarkers(a, b) {
6518 var lenDiff = a.lines.length - b.lines.length;
6519 if (lenDiff != 0) return lenDiff;
6520 var aPos = a.find(), bPos = b.find();
6521 var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
6522 if (fromCmp) return -fromCmp;
6523 var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
6524 if (toCmp) return toCmp;
6525 return b.id - a.id;
6526 }
6527
6528 // Find out whether a line ends or starts in a collapsed span. If
6529 // so, return the marker for that span.
6530 function collapsedSpanAtSide(line, start) {
6531 var sps = sawCollapsedSpans && line.markedSpans, found;
6532 if (sps) for (var sp, i = 0; i < sps.length; ++i) {
6533 sp = sps[i];
6534 if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
6535 (!found || compareCollapsedMarkers(found, sp.marker) < 0))
6536 found = sp.marker;
6537 }
6538 return found;
6539 }
6540 function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
6541 function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
6542
6543 // Test whether there exists a collapsed span that partially
6544 // overlaps (covers the start or end, but not both) of a new span.
6545 // Such overlap is not allowed.
6546 function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
6547 var line = getLine(doc, lineNo);
6548 var sps = sawCollapsedSpans && line.markedSpans;
6549 if (sps) for (var i = 0; i < sps.length; ++i) {
6550 var sp = sps[i];
6551 if (!sp.marker.collapsed) continue;
6552 var found = sp.marker.find(0);
6553 var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
6554 var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
6555 if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
6556 if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
6557 fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))
6558 return true;
6559 }
6560 }
6561
6562 // A visual line is a line as drawn on the screen. Folding, for
6563 // example, can cause multiple logical lines to appear on the same
6564 // visual line. This finds the start of the visual line that the
6565 // given line is part of (usually that is the line itself).
6566 function visualLine(line) {
6567 var merged;
6568 while (merged = collapsedSpanAtStart(line))
6569 line = merged.find(-1, true).line;
6570 return line;
6571 }
6572
6573 // Returns an array of logical lines that continue the visual line
6574 // started by the argument, or undefined if there are no such lines.
6575 function visualLineContinued(line) {
6576 var merged, lines;
6577 while (merged = collapsedSpanAtEnd(line)) {
6578 line = merged.find(1, true).line;
6579 (lines || (lines = [])).push(line);
6580 }
6581 return lines;
6582 }
6583
6584 // Get the line number of the start of the visual line that the
6585 // given line number is part of.
6586 function visualLineNo(doc, lineN) {
6587 var line = getLine(doc, lineN), vis = visualLine(line);
6588 if (line == vis) return lineN;
6589 return lineNo(vis);
6590 }
6591 // Get the line number of the start of the next visual line after
6592 // the given line.
6593 function visualLineEndNo(doc, lineN) {
6594 if (lineN > doc.lastLine()) return lineN;
6595 var line = getLine(doc, lineN), merged;
6596 if (!lineIsHidden(doc, line)) return lineN;
6597 while (merged = collapsedSpanAtEnd(line))
6598 line = merged.find(1, true).line;
6599 return lineNo(line) + 1;
6600 }
6601
6602 // Compute whether a line is hidden. Lines count as hidden when they
6603 // are part of a visual line that starts with another line, or when
6604 // they are entirely covered by collapsed, non-widget span.
6605 function lineIsHidden(doc, line) {
6606 var sps = sawCollapsedSpans && line.markedSpans;
6607 if (sps) for (var sp, i = 0; i < sps.length; ++i) {
6608 sp = sps[i];
6609 if (!sp.marker.collapsed) continue;
6610 if (sp.from == null) return true;
6611 if (sp.marker.widgetNode) continue;
6612 if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
6613 return true;
6614 }
6615 }
6616 function lineIsHiddenInner(doc, line, span) {
6617 if (span.to == null) {
6618 var end = span.marker.find(1, true);
6619 return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
6620 }
6621 if (span.marker.inclusiveRight && span.to == line.text.length)
6622 return true;
6623 for (var sp, i = 0; i < line.markedSpans.length; ++i) {
6624 sp = line.markedSpans[i];
6625 if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
6626 (sp.to == null || sp.to != span.from) &&
6627 (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
6628 lineIsHiddenInner(doc, line, sp)) return true;
6629 }
6630 }
6631
6632 // LINE WIDGETS
6633
6634 // Line widgets are block elements displayed above or below a line.
6635
6636 var LineWidget = CodeMirror.LineWidget = function(doc, node, options) {
6637 if (options) for (var opt in options) if (options.hasOwnProperty(opt))
6638 this[opt] = options[opt];
6639 this.doc = doc;
6640 this.node = node;
6641 };
6642 eventMixin(LineWidget);
6643
6644 function adjustScrollWhenAboveVisible(cm, line, diff) {
6645 if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
6646 addToScrollPos(cm, null, diff);
6647 }
6648
6649 LineWidget.prototype.clear = function() {
6650 var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
6651 if (no == null || !ws) return;
6652 for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
6653 if (!ws.length) line.widgets = null;
6654 var height = widgetHeight(this);
6655 updateLineHeight(line, Math.max(0, line.height - height));
6656 if (cm) runInOp(cm, function() {
6657 adjustScrollWhenAboveVisible(cm, line, -height);
6658 regLineChange(cm, no, "widget");
6659 });
6660 };
6661 LineWidget.prototype.changed = function() {
6662 var oldH = this.height, cm = this.doc.cm, line = this.line;
6663 this.height = null;
6664 var diff = widgetHeight(this) - oldH;
6665 if (!diff) return;
6666 updateLineHeight(line, line.height + diff);
6667 if (cm) runInOp(cm, function() {
6668 cm.curOp.forceUpdate = true;
6669 adjustScrollWhenAboveVisible(cm, line, diff);
6670 });
6671 };
6672
6673 function widgetHeight(widget) {
6674 if (widget.height != null) return widget.height;
6675 var cm = widget.doc.cm;
6676 if (!cm) return 0;
6677 if (!contains(document.body, widget.node)) {
6678 var parentStyle = "position: relative;";
6679 if (widget.coverGutter)
6680 parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;";
6681 if (widget.noHScroll)
6682 parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
6683 removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
6684 }
6685 return widget.height = widget.node.parentNode.offsetHeight;
6686 }
6687
6688 function addLineWidget(doc, handle, node, options) {
6689 var widget = new LineWidget(doc, node, options);
6690 var cm = doc.cm;
6691 if (cm && widget.noHScroll) cm.display.alignWidgets = true;
6692 changeLine(doc, handle, "widget", function(line) {
6693 var widgets = line.widgets || (line.widgets = []);
6694 if (widget.insertAt == null) widgets.push(widget);
6695 else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
6696 widget.line = line;
6697 if (cm && !lineIsHidden(doc, line)) {
6698 var aboveVisible = heightAtLine(line) < doc.scrollTop;
6699 updateLineHeight(line, line.height + widgetHeight(widget));
6700 if (aboveVisible) addToScrollPos(cm, null, widget.height);
6701 cm.curOp.forceUpdate = true;
6702 }
6703 return true;
6704 });
6705 return widget;
6706 }
6707
6708 // LINE DATA STRUCTURE
6709
6710 // Line objects. These hold state related to a line, including
6711 // highlighting info (the styles array).
6712 var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
6713 this.text = text;
6714 attachMarkedSpans(this, markedSpans);
6715 this.height = estimateHeight ? estimateHeight(this) : 1;
6716 };
6717 eventMixin(Line);
6718 Line.prototype.lineNo = function() { return lineNo(this); };
6719
6720 // Change the content (text, markers) of a line. Automatically
6721 // invalidates cached information and tries to re-estimate the
6722 // line's height.
6723 function updateLine(line, text, markedSpans, estimateHeight) {
6724 line.text = text;
6725 if (line.stateAfter) line.stateAfter = null;
6726 if (line.styles) line.styles = null;
6727 if (line.order != null) line.order = null;
6728 detachMarkedSpans(line);
6729 attachMarkedSpans(line, markedSpans);
6730 var estHeight = estimateHeight ? estimateHeight(line) : 1;
6731 if (estHeight != line.height) updateLineHeight(line, estHeight);
6732 }
6733
6734 // Detach a line from the document tree and its markers.
6735 function cleanUpLine(line) {
6736 line.parent = null;
6737 detachMarkedSpans(line);
6738 }
6739
6740 function extractLineClasses(type, output) {
6741 if (type) for (;;) {
6742 var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
6743 if (!lineClass) break;
6744 type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
6745 var prop = lineClass[1] ? "bgClass" : "textClass";
6746 if (output[prop] == null)
6747 output[prop] = lineClass[2];
6748 else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
6749 output[prop] += " " + lineClass[2];
6750 }
6751 return type;
6752 }
6753
6754 function callBlankLine(mode, state) {
6755 if (mode.blankLine) return mode.blankLine(state);
6756 if (!mode.innerMode) return;
6757 var inner = CodeMirror.innerMode(mode, state);
6758 if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
6759 }
6760
6761 function readToken(mode, stream, state, inner) {
6762 for (var i = 0; i < 10; i++) {
6763 if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
6764 var style = mode.token(stream, state);
6765 if (stream.pos > stream.start) return style;
6766 }
6767 throw new Error("Mode " + mode.name + " failed to advance stream.");
6768 }
6769
6770 // Utility for getTokenAt and getLineTokens
6771 function takeToken(cm, pos, precise, asArray) {
6772 function getObj(copy) {
6773 return {start: stream.start, end: stream.pos,
6774 string: stream.current(),
6775 type: style || null,
6776 state: copy ? copyState(doc.mode, state) : state};
6777 }
6778
6779 var doc = cm.doc, mode = doc.mode, style;
6780 pos = clipPos(doc, pos);
6781 var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
6782 var stream = new StringStream(line.text, cm.options.tabSize), tokens;
6783 if (asArray) tokens = [];
6784 while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
6785 stream.start = stream.pos;
6786 style = readToken(mode, stream, state);
6787 if (asArray) tokens.push(getObj(true));
6788 }
6789 return asArray ? tokens : getObj();
6790 }
6791
6792 // Run the given mode's parser over a line, calling f for each token.
6793 function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
6794 var flattenSpans = mode.flattenSpans;
6795 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
6796 var curStart = 0, curStyle = null;
6797 var stream = new StringStream(text, cm.options.tabSize), style;
6798 var inner = cm.options.addModeClass && [null];
6799 if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
6800 while (!stream.eol()) {
6801 if (stream.pos > cm.options.maxHighlightLength) {
6802 flattenSpans = false;
6803 if (forceToEnd) processLine(cm, text, state, stream.pos);
6804 stream.pos = text.length;
6805 style = null;
6806 } else {
6807 style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
6808 }
6809 if (inner) {
6810 var mName = inner[0].name;
6811 if (mName) style = "m-" + (style ? mName + " " + style : mName);
6812 }
6813 if (!flattenSpans || curStyle != style) {
6814 while (curStart < stream.start) {
6815 curStart = Math.min(stream.start, curStart + 50000);
6816 f(curStart, curStyle);
6817 }
6818 curStyle = style;
6819 }
6820 stream.start = stream.pos;
6821 }
6822 while (curStart < stream.pos) {
6823 // Webkit seems to refuse to render text nodes longer than 57444 characters
6824 var pos = Math.min(stream.pos, curStart + 50000);
6825 f(pos, curStyle);
6826 curStart = pos;
6827 }
6828 }
6829
6830 // Compute a style array (an array starting with a mode generation
6831 // -- for invalidation -- followed by pairs of end positions and
6832 // style strings), which is used to highlight the tokens on the
6833 // line.
6834 function highlightLine(cm, line, state, forceToEnd) {
6835 // A styles array always starts with a number identifying the
6836 // mode/overlays that it is based on (for easy invalidation).
6837 var st = [cm.state.modeGen], lineClasses = {};
6838 // Compute the base array of styles
6839 runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
6840 st.push(end, style);
6841 }, lineClasses, forceToEnd);
6842
6843 // Run overlays, adjust style array.
6844 for (var o = 0; o < cm.state.overlays.length; ++o) {
6845 var overlay = cm.state.overlays[o], i = 1, at = 0;
6846 runMode(cm, line.text, overlay.mode, true, function(end, style) {
6847 var start = i;
6848 // Ensure there's a token end at the current position, and that i points at it
6849 while (at < end) {
6850 var i_end = st[i];
6851 if (i_end > end)
6852 st.splice(i, 1, end, st[i+1], i_end);
6853 i += 2;
6854 at = Math.min(end, i_end);
6855 }
6856 if (!style) return;
6857 if (overlay.opaque) {
6858 st.splice(start, i - start, end, "cm-overlay " + style);
6859 i = start + 2;
6860 } else {
6861 for (; start < i; start += 2) {
6862 var cur = st[start+1];
6863 st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
6864 }
6865 }
6866 }, lineClasses);
6867 }
6868
6869 return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
6870 }
6871
6872 function getLineStyles(cm, line, updateFrontier) {
6873 if (!line.styles || line.styles[0] != cm.state.modeGen) {
6874 var state = getStateBefore(cm, lineNo(line));
6875 var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state);
6876 line.stateAfter = state;
6877 line.styles = result.styles;
6878 if (result.classes) line.styleClasses = result.classes;
6879 else if (line.styleClasses) line.styleClasses = null;
6880 if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
6881 }
6882 return line.styles;
6883 }
6884
6885 // Lightweight form of highlight -- proceed over this line and
6886 // update state, but don't save a style array. Used for lines that
6887 // aren't currently visible.
6888 function processLine(cm, text, state, startAt) {
6889 var mode = cm.doc.mode;
6890 var stream = new StringStream(text, cm.options.tabSize);
6891 stream.start = stream.pos = startAt || 0;
6892 if (text == "") callBlankLine(mode, state);
6893 while (!stream.eol()) {
6894 readToken(mode, stream, state);
6895 stream.start = stream.pos;
6896 }
6897 }
6898
6899 // Convert a style as returned by a mode (either null, or a string
6900 // containing one or more styles) to a CSS style. This is cached,
6901 // and also looks for line-wide styles.
6902 var styleToClassCache = {}, styleToClassCacheWithMode = {};
6903 function interpretTokenStyle(style, options) {
6904 if (!style || /^\s*$/.test(style)) return null;
6905 var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
6906 return cache[style] ||
6907 (cache[style] = style.replace(/\S+/g, "cm-$&"));
6908 }
6909
6910 // Render the DOM representation of the text of a line. Also builds
6911 // up a 'line map', which points at the DOM nodes that represent
6912 // specific stretches of text, and is used by the measuring code.
6913 // The returned object contains the DOM node, this map, and
6914 // information about line-wide styles that were set by the mode.
6915 function buildLineContent(cm, lineView) {
6916 // The padding-right forces the element to have a 'border', which
6917 // is needed on Webkit to be able to get line-level bounding
6918 // rectangles for it (in measureChar).
6919 var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
6920 var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
6921 col: 0, pos: 0, cm: cm,
6922 splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
6923 lineView.measure = {};
6924
6925 // Iterate over the logical lines that make up this visual line.
6926 for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
6927 var line = i ? lineView.rest[i - 1] : lineView.line, order;
6928 builder.pos = 0;
6929 builder.addToken = buildToken;
6930 // Optionally wire in some hacks into the token-rendering
6931 // algorithm, to deal with browser quirks.
6932 if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
6933 builder.addToken = buildTokenBadBidi(builder.addToken, order);
6934 builder.map = [];
6935 var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
6936 insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
6937 if (line.styleClasses) {
6938 if (line.styleClasses.bgClass)
6939 builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
6940 if (line.styleClasses.textClass)
6941 builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
6942 }
6943
6944 // Ensure at least a single node is present, for measuring.
6945 if (builder.map.length == 0)
6946 builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
6947
6948 // Store the map and a cache object for the current logical line
6949 if (i == 0) {
6950 lineView.measure.map = builder.map;
6951 lineView.measure.cache = {};
6952 } else {
6953 (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
6954 (lineView.measure.caches || (lineView.measure.caches = [])).push({});
6955 }
6956 }
6957
6958 // See issue #2901
6959 if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className))
6960 builder.content.className = "cm-tab-wrap-hack";
6961
6962 signal(cm, "renderLine", cm, lineView.line, builder.pre);
6963 if (builder.pre.className)
6964 builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
6965
6966 return builder;
6967 }
6968
6969 function defaultSpecialCharPlaceholder(ch) {
6970 var token = elt("span", "\u2022", "cm-invalidchar");
6971 token.title = "\\u" + ch.charCodeAt(0).toString(16);
6972 token.setAttribute("aria-label", token.title);
6973 return token;
6974 }
6975
6976 // Build up the DOM representation for a single token, and add it to
6977 // the line map. Takes care to render special characters separately.
6978 function buildToken(builder, text, style, startStyle, endStyle, title, css) {
6979 if (!text) return;
6980 var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text;
6981 var special = builder.cm.state.specialChars, mustWrap = false;
6982 if (!special.test(text)) {
6983 builder.col += text.length;
6984 var content = document.createTextNode(displayText);
6985 builder.map.push(builder.pos, builder.pos + text.length, content);
6986 if (ie && ie_version < 9) mustWrap = true;
6987 builder.pos += text.length;
6988 } else {
6989 var content = document.createDocumentFragment(), pos = 0;
6990 while (true) {
6991 special.lastIndex = pos;
6992 var m = special.exec(text);
6993 var skipped = m ? m.index - pos : text.length - pos;
6994 if (skipped) {
6995 var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
6996 if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
6997 else content.appendChild(txt);
6998 builder.map.push(builder.pos, builder.pos + skipped, txt);
6999 builder.col += skipped;
7000 builder.pos += skipped;
7001 }
7002 if (!m) break;
7003 pos += skipped + 1;
7004 if (m[0] == "\t") {
7005 var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
7006 var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
7007 txt.setAttribute("role", "presentation");
7008 txt.setAttribute("cm-text", "\t");
7009 builder.col += tabWidth;
7010 } else if (m[0] == "\r" || m[0] == "\n") {
7011 var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
7012 txt.setAttribute("cm-text", m[0]);
7013 builder.col += 1;
7014 } else {
7015 var txt = builder.cm.options.specialCharPlaceholder(m[0]);
7016 txt.setAttribute("cm-text", m[0]);
7017 if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
7018 else content.appendChild(txt);
7019 builder.col += 1;
7020 }
7021 builder.map.push(builder.pos, builder.pos + 1, txt);
7022 builder.pos++;
7023 }
7024 }
7025 if (style || startStyle || endStyle || mustWrap || css) {
7026 var fullStyle = style || "";
7027 if (startStyle) fullStyle += startStyle;
7028 if (endStyle) fullStyle += endStyle;
7029 var token = elt("span", [content], fullStyle, css);
7030 if (title) token.title = title;
7031 return builder.content.appendChild(token);
7032 }
7033 builder.content.appendChild(content);
7034 }
7035
7036 function splitSpaces(old) {
7037 var out = " ";
7038 for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
7039 out += " ";
7040 return out;
7041 }
7042
7043 // Work around nonsense dimensions being reported for stretches of
7044 // right-to-left text.
7045 function buildTokenBadBidi(inner, order) {
7046 return function(builder, text, style, startStyle, endStyle, title, css) {
7047 style = style ? style + " cm-force-border" : "cm-force-border";
7048 var start = builder.pos, end = start + text.length;
7049 for (;;) {
7050 // Find the part that overlaps with the start of this text
7051 for (var i = 0; i < order.length; i++) {
7052 var part = order[i];
7053 if (part.to > start && part.from <= start) break;
7054 }
7055 if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css);
7056 inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
7057 startStyle = null;
7058 text = text.slice(part.to - start);
7059 start = part.to;
7060 }
7061 };
7062 }
7063
7064 function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
7065 var widget = !ignoreWidget && marker.widgetNode;
7066 if (widget) builder.map.push(builder.pos, builder.pos + size, widget);
7067 if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
7068 if (!widget)
7069 widget = builder.content.appendChild(document.createElement("span"));
7070 widget.setAttribute("cm-marker", marker.id);
7071 }
7072 if (widget) {
7073 builder.cm.display.input.setUneditable(widget);
7074 builder.content.appendChild(widget);
7075 }
7076 builder.pos += size;
7077 }
7078
7079 // Outputs a number of spans to make up a line, taking highlighting
7080 // and marked text into account.
7081 function insertLineContent(line, builder, styles) {
7082 var spans = line.markedSpans, allText = line.text, at = 0;
7083 if (!spans) {
7084 for (var i = 1; i < styles.length; i+=2)
7085 builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
7086 return;
7087 }
7088
7089 var len = allText.length, pos = 0, i = 1, text = "", style, css;
7090 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
7091 for (;;) {
7092 if (nextChange == pos) { // Update current marker set
7093 spanStyle = spanEndStyle = spanStartStyle = title = css = "";
7094 collapsed = null; nextChange = Infinity;
7095 var foundBookmarks = [], endStyles
7096 for (var j = 0; j < spans.length; ++j) {
7097 var sp = spans[j], m = sp.marker;
7098 if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
7099 foundBookmarks.push(m);
7100 } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
7101 if (sp.to != null && sp.to != pos && nextChange > sp.to) {
7102 nextChange = sp.to;
7103 spanEndStyle = "";
7104 }
7105 if (m.className) spanStyle += " " + m.className;
7106 if (m.css) css = (css ? css + ";" : "") + m.css;
7107 if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
7108 if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to)
7109 if (m.title && !title) title = m.title;
7110 if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
7111 collapsed = sp;
7112 } else if (sp.from > pos && nextChange > sp.from) {
7113 nextChange = sp.from;
7114 }
7115 }
7116 if (endStyles) for (var j = 0; j < endStyles.length; j += 2)
7117 if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j]
7118
7119 if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j)
7120 buildCollapsedSpan(builder, 0, foundBookmarks[j]);
7121 if (collapsed && (collapsed.from || 0) == pos) {
7122 buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
7123 collapsed.marker, collapsed.from == null);
7124 if (collapsed.to == null) return;
7125 if (collapsed.to == pos) collapsed = false;
7126 }
7127 }
7128 if (pos >= len) break;
7129
7130 var upto = Math.min(len, nextChange);
7131 while (true) {
7132 if (text) {
7133 var end = pos + text.length;
7134 if (!collapsed) {
7135 var tokenText = end > upto ? text.slice(0, upto - pos) : text;
7136 builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
7137 spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
7138 }
7139 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
7140 pos = end;
7141 spanStartStyle = "";
7142 }
7143 text = allText.slice(at, at = styles[i++]);
7144 style = interpretTokenStyle(styles[i++], builder.cm.options);
7145 }
7146 }
7147 }
4702 }
7148
4703
7149 // DOCUMENT DATA STRUCTURE
4704 // DOCUMENT DATA STRUCTURE
@@ -7153,20 +4708,21 b''
7153 // widgets and marker elements with the text behave more intuitive.
4708 // widgets and marker elements with the text behave more intuitive.
7154 function isWholeLineUpdate(doc, change) {
4709 function isWholeLineUpdate(doc, change) {
7155 return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
4710 return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
7156 (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
4711 (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
7157 }
4712 }
7158
4713
7159 // Perform a change on the document data structure.
4714 // Perform a change on the document data structure.
7160 function updateDoc(doc, change, markedSpans, estimateHeight) {
4715 function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
7161 function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
4716 function spansFor(n) {return markedSpans ? markedSpans[n] : null}
7162 function update(line, text, spans) {
4717 function update(line, text, spans) {
7163 updateLine(line, text, spans, estimateHeight);
4718 updateLine(line, text, spans, estimateHeight$$1);
7164 signalLater(line, "change", line, change);
4719 signalLater(line, "change", line, change);
7165 }
4720 }
7166 function linesFor(start, end) {
4721 function linesFor(start, end) {
7167 for (var i = start, result = []; i < end; ++i)
4722 var result = [];
7168 result.push(new Line(text[i], spansFor(i), estimateHeight));
4723 for (var i = start; i < end; ++i)
7169 return result;
4724 { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
4725 return result
7170 }
4726 }
7171
4727
7172 var from = change.from, to = change.to, text = change.text;
4728 var from = change.from, to = change.to, text = change.text;
@@ -7182,16 +4738,16 b''
7182 // sure line objects move the way they are supposed to.
4738 // sure line objects move the way they are supposed to.
7183 var added = linesFor(0, text.length - 1);
4739 var added = linesFor(0, text.length - 1);
7184 update(lastLine, lastLine.text, lastSpans);
4740 update(lastLine, lastLine.text, lastSpans);
7185 if (nlines) doc.remove(from.line, nlines);
4741 if (nlines) { doc.remove(from.line, nlines); }
7186 if (added.length) doc.insert(from.line, added);
4742 if (added.length) { doc.insert(from.line, added); }
7187 } else if (firstLine == lastLine) {
4743 } else if (firstLine == lastLine) {
7188 if (text.length == 1) {
4744 if (text.length == 1) {
7189 update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
4745 update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
7190 } else {
4746 } else {
7191 var added = linesFor(1, text.length - 1);
4747 var added$1 = linesFor(1, text.length - 1);
7192 added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
4748 added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
7193 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
4749 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
7194 doc.insert(from.line + 1, added);
4750 doc.insert(from.line + 1, added$1);
7195 }
4751 }
7196 } else if (text.length == 1) {
4752 } else if (text.length == 1) {
7197 update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
4753 update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
@@ -7199,671 +4755,52 b''
7199 } else {
4755 } else {
7200 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
4756 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
7201 update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
4757 update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
7202 var added = linesFor(1, text.length - 1);
4758 var added$2 = linesFor(1, text.length - 1);
7203 if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
4759 if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
7204 doc.insert(from.line + 1, added);
4760 doc.insert(from.line + 1, added$2);
7205 }
4761 }
7206
4762
7207 signalLater(doc, "change", doc, change);
4763 signalLater(doc, "change", doc, change);
7208 }
4764 }
7209
4765
7210 // The document is represented as a BTree consisting of leaves, with
7211 // chunk of lines in them, and branches, with up to ten leaves or
7212 // other branch nodes below them. The top node is always a branch
7213 // node, and is the document object itself (meaning it has
7214 // additional methods and properties).
7215 //
7216 // All nodes have parent links. The tree is used both to go from
7217 // line numbers to line objects, and to go from objects to numbers.
7218 // It also indexes by height, and is used to convert between height
7219 // and line object, and to find the total height of the document.
7220 //
7221 // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
7222
7223 function LeafChunk(lines) {
7224 this.lines = lines;
7225 this.parent = null;
7226 for (var i = 0, height = 0; i < lines.length; ++i) {
7227 lines[i].parent = this;
7228 height += lines[i].height;
7229 }
7230 this.height = height;
7231 }
7232
7233 LeafChunk.prototype = {
7234 chunkSize: function() { return this.lines.length; },
7235 // Remove the n lines at offset 'at'.
7236 removeInner: function(at, n) {
7237 for (var i = at, e = at + n; i < e; ++i) {
7238 var line = this.lines[i];
7239 this.height -= line.height;
7240 cleanUpLine(line);
7241 signalLater(line, "delete");
7242 }
7243 this.lines.splice(at, n);
7244 },
7245 // Helper used to collapse a small branch into a single leaf.
7246 collapse: function(lines) {
7247 lines.push.apply(lines, this.lines);
7248 },
7249 // Insert the given array of lines at offset 'at', count them as
7250 // having the given height.
7251 insertInner: function(at, lines, height) {
7252 this.height += height;
7253 this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
7254 for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
7255 },
7256 // Used to iterate over a part of the tree.
7257 iterN: function(at, n, op) {
7258 for (var e = at + n; at < e; ++at)
7259 if (op(this.lines[at])) return true;
7260 }
7261 };
7262
7263 function BranchChunk(children) {
7264 this.children = children;
7265 var size = 0, height = 0;
7266 for (var i = 0; i < children.length; ++i) {
7267 var ch = children[i];
7268 size += ch.chunkSize(); height += ch.height;
7269 ch.parent = this;
7270 }
7271 this.size = size;
7272 this.height = height;
7273 this.parent = null;
7274 }
7275
7276 BranchChunk.prototype = {
7277 chunkSize: function() { return this.size; },
7278 removeInner: function(at, n) {
7279 this.size -= n;
7280 for (var i = 0; i < this.children.length; ++i) {
7281 var child = this.children[i], sz = child.chunkSize();
7282 if (at < sz) {
7283 var rm = Math.min(n, sz - at), oldHeight = child.height;
7284 child.removeInner(at, rm);
7285 this.height -= oldHeight - child.height;
7286 if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
7287 if ((n -= rm) == 0) break;
7288 at = 0;
7289 } else at -= sz;
7290 }
7291 // If the result is smaller than 25 lines, ensure that it is a
7292 // single leaf node.
7293 if (this.size - n < 25 &&
7294 (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
7295 var lines = [];
7296 this.collapse(lines);
7297 this.children = [new LeafChunk(lines)];
7298 this.children[0].parent = this;
7299 }
7300 },
7301 collapse: function(lines) {
7302 for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
7303 },
7304 insertInner: function(at, lines, height) {
7305 this.size += lines.length;
7306 this.height += height;
7307 for (var i = 0; i < this.children.length; ++i) {
7308 var child = this.children[i], sz = child.chunkSize();
7309 if (at <= sz) {
7310 child.insertInner(at, lines, height);
7311 if (child.lines && child.lines.length > 50) {
7312 while (child.lines.length > 50) {
7313 var spilled = child.lines.splice(child.lines.length - 25, 25);
7314 var newleaf = new LeafChunk(spilled);
7315 child.height -= newleaf.height;
7316 this.children.splice(i + 1, 0, newleaf);
7317 newleaf.parent = this;
7318 }
7319 this.maybeSpill();
7320 }
7321 break;
7322 }
7323 at -= sz;
7324 }
7325 },
7326 // When a node has grown, check whether it should be split.
7327 maybeSpill: function() {
7328 if (this.children.length <= 10) return;
7329 var me = this;
7330 do {
7331 var spilled = me.children.splice(me.children.length - 5, 5);
7332 var sibling = new BranchChunk(spilled);
7333 if (!me.parent) { // Become the parent node
7334 var copy = new BranchChunk(me.children);
7335 copy.parent = me;
7336 me.children = [copy, sibling];
7337 me = copy;
7338 } else {
7339 me.size -= sibling.size;
7340 me.height -= sibling.height;
7341 var myIndex = indexOf(me.parent.children, me);
7342 me.parent.children.splice(myIndex + 1, 0, sibling);
7343 }
7344 sibling.parent = me.parent;
7345 } while (me.children.length > 10);
7346 me.parent.maybeSpill();
7347 },
7348 iterN: function(at, n, op) {
7349 for (var i = 0; i < this.children.length; ++i) {
7350 var child = this.children[i], sz = child.chunkSize();
7351 if (at < sz) {
7352 var used = Math.min(n, sz - at);
7353 if (child.iterN(at, used, op)) return true;
7354 if ((n -= used) == 0) break;
7355 at = 0;
7356 } else at -= sz;
7357 }
7358 }
7359 };
7360
7361 var nextDocId = 0;
7362 var Doc = CodeMirror.Doc = function(text, mode, firstLine, lineSep) {
7363 if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep);
7364 if (firstLine == null) firstLine = 0;
7365
7366 BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
7367 this.first = firstLine;
7368 this.scrollTop = this.scrollLeft = 0;
7369 this.cantEdit = false;
7370 this.cleanGeneration = 1;
7371 this.frontier = firstLine;
7372 var start = Pos(firstLine, 0);
7373 this.sel = simpleSelection(start);
7374 this.history = new History(null);
7375 this.id = ++nextDocId;
7376 this.modeOption = mode;
7377 this.lineSep = lineSep;
7378 this.extend = false;
7379
7380 if (typeof text == "string") text = this.splitLines(text);
7381 updateDoc(this, {from: start, to: start, text: text});
7382 setSelection(this, simpleSelection(start), sel_dontScroll);
7383 };
7384
7385 Doc.prototype = createObj(BranchChunk.prototype, {
7386 constructor: Doc,
7387 // Iterate over the document. Supports two forms -- with only one
7388 // argument, it calls that for each line in the document. With
7389 // three, it iterates over the range given by the first two (with
7390 // the second being non-inclusive).
7391 iter: function(from, to, op) {
7392 if (op) this.iterN(from - this.first, to - from, op);
7393 else this.iterN(this.first, this.first + this.size, from);
7394 },
7395
7396 // Non-public interface for adding and removing lines.
7397 insert: function(at, lines) {
7398 var height = 0;
7399 for (var i = 0; i < lines.length; ++i) height += lines[i].height;
7400 this.insertInner(at - this.first, lines, height);
7401 },
7402 remove: function(at, n) { this.removeInner(at - this.first, n); },
7403
7404 // From here, the methods are part of the public interface. Most
7405 // are also available from CodeMirror (editor) instances.
7406
7407 getValue: function(lineSep) {
7408 var lines = getLines(this, this.first, this.first + this.size);
7409 if (lineSep === false) return lines;
7410 return lines.join(lineSep || this.lineSeparator());
7411 },
7412 setValue: docMethodOp(function(code) {
7413 var top = Pos(this.first, 0), last = this.first + this.size - 1;
7414 makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
7415 text: this.splitLines(code), origin: "setValue", full: true}, true);
7416 setSelection(this, simpleSelection(top));
7417 }),
7418 replaceRange: function(code, from, to, origin) {
7419 from = clipPos(this, from);
7420 to = to ? clipPos(this, to) : from;
7421 replaceRange(this, code, from, to, origin);
7422 },
7423 getRange: function(from, to, lineSep) {
7424 var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
7425 if (lineSep === false) return lines;
7426 return lines.join(lineSep || this.lineSeparator());
7427 },
7428
7429 getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
7430
7431 getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
7432 getLineNumber: function(line) {return lineNo(line);},
7433
7434 getLineHandleVisualStart: function(line) {
7435 if (typeof line == "number") line = getLine(this, line);
7436 return visualLine(line);
7437 },
7438
7439 lineCount: function() {return this.size;},
7440 firstLine: function() {return this.first;},
7441 lastLine: function() {return this.first + this.size - 1;},
7442
7443 clipPos: function(pos) {return clipPos(this, pos);},
7444
7445 getCursor: function(start) {
7446 var range = this.sel.primary(), pos;
7447 if (start == null || start == "head") pos = range.head;
7448 else if (start == "anchor") pos = range.anchor;
7449 else if (start == "end" || start == "to" || start === false) pos = range.to();
7450 else pos = range.from();
7451 return pos;
7452 },
7453 listSelections: function() { return this.sel.ranges; },
7454 somethingSelected: function() {return this.sel.somethingSelected();},
7455
7456 setCursor: docMethodOp(function(line, ch, options) {
7457 setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
7458 }),
7459 setSelection: docMethodOp(function(anchor, head, options) {
7460 setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
7461 }),
7462 extendSelection: docMethodOp(function(head, other, options) {
7463 extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
7464 }),
7465 extendSelections: docMethodOp(function(heads, options) {
7466 extendSelections(this, clipPosArray(this, heads), options);
7467 }),
7468 extendSelectionsBy: docMethodOp(function(f, options) {
7469 var heads = map(this.sel.ranges, f);
7470 extendSelections(this, clipPosArray(this, heads), options);
7471 }),
7472 setSelections: docMethodOp(function(ranges, primary, options) {
7473 if (!ranges.length) return;
7474 for (var i = 0, out = []; i < ranges.length; i++)
7475 out[i] = new Range(clipPos(this, ranges[i].anchor),
7476 clipPos(this, ranges[i].head));
7477 if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
7478 setSelection(this, normalizeSelection(out, primary), options);
7479 }),
7480 addSelection: docMethodOp(function(anchor, head, options) {
7481 var ranges = this.sel.ranges.slice(0);
7482 ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
7483 setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
7484 }),
7485
7486 getSelection: function(lineSep) {
7487 var ranges = this.sel.ranges, lines;
7488 for (var i = 0; i < ranges.length; i++) {
7489 var sel = getBetween(this, ranges[i].from(), ranges[i].to());
7490 lines = lines ? lines.concat(sel) : sel;
7491 }
7492 if (lineSep === false) return lines;
7493 else return lines.join(lineSep || this.lineSeparator());
7494 },
7495 getSelections: function(lineSep) {
7496 var parts = [], ranges = this.sel.ranges;
7497 for (var i = 0; i < ranges.length; i++) {
7498 var sel = getBetween(this, ranges[i].from(), ranges[i].to());
7499 if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator());
7500 parts[i] = sel;
7501 }
7502 return parts;
7503 },
7504 replaceSelection: function(code, collapse, origin) {
7505 var dup = [];
7506 for (var i = 0; i < this.sel.ranges.length; i++)
7507 dup[i] = code;
7508 this.replaceSelections(dup, collapse, origin || "+input");
7509 },
7510 replaceSelections: docMethodOp(function(code, collapse, origin) {
7511 var changes = [], sel = this.sel;
7512 for (var i = 0; i < sel.ranges.length; i++) {
7513 var range = sel.ranges[i];
7514 changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};
7515 }
7516 var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
7517 for (var i = changes.length - 1; i >= 0; i--)
7518 makeChange(this, changes[i]);
7519 if (newSel) setSelectionReplaceHistory(this, newSel);
7520 else if (this.cm) ensureCursorVisible(this.cm);
7521 }),
7522 undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
7523 redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
7524 undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
7525 redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
7526
7527 setExtending: function(val) {this.extend = val;},
7528 getExtending: function() {return this.extend;},
7529
7530 historySize: function() {
7531 var hist = this.history, done = 0, undone = 0;
7532 for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
7533 for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
7534 return {undo: done, redo: undone};
7535 },
7536 clearHistory: function() {this.history = new History(this.history.maxGeneration);},
7537
7538 markClean: function() {
7539 this.cleanGeneration = this.changeGeneration(true);
7540 },
7541 changeGeneration: function(forceSplit) {
7542 if (forceSplit)
7543 this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
7544 return this.history.generation;
7545 },
7546 isClean: function (gen) {
7547 return this.history.generation == (gen || this.cleanGeneration);
7548 },
7549
7550 getHistory: function() {
7551 return {done: copyHistoryArray(this.history.done),
7552 undone: copyHistoryArray(this.history.undone)};
7553 },
7554 setHistory: function(histData) {
7555 var hist = this.history = new History(this.history.maxGeneration);
7556 hist.done = copyHistoryArray(histData.done.slice(0), null, true);
7557 hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
7558 },
7559
7560 addLineClass: docMethodOp(function(handle, where, cls) {
7561 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
7562 var prop = where == "text" ? "textClass"
7563 : where == "background" ? "bgClass"
7564 : where == "gutter" ? "gutterClass" : "wrapClass";
7565 if (!line[prop]) line[prop] = cls;
7566 else if (classTest(cls).test(line[prop])) return false;
7567 else line[prop] += " " + cls;
7568 return true;
7569 });
7570 }),
7571 removeLineClass: docMethodOp(function(handle, where, cls) {
7572 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
7573 var prop = where == "text" ? "textClass"
7574 : where == "background" ? "bgClass"
7575 : where == "gutter" ? "gutterClass" : "wrapClass";
7576 var cur = line[prop];
7577 if (!cur) return false;
7578 else if (cls == null) line[prop] = null;
7579 else {
7580 var found = cur.match(classTest(cls));
7581 if (!found) return false;
7582 var end = found.index + found[0].length;
7583 line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
7584 }
7585 return true;
7586 });
7587 }),
7588
7589 addLineWidget: docMethodOp(function(handle, node, options) {
7590 return addLineWidget(this, handle, node, options);
7591 }),
7592 removeLineWidget: function(widget) { widget.clear(); },
7593
7594 markText: function(from, to, options) {
7595 return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range");
7596 },
7597 setBookmark: function(pos, options) {
7598 var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
7599 insertLeft: options && options.insertLeft,
7600 clearWhenEmpty: false, shared: options && options.shared,
7601 handleMouseEvents: options && options.handleMouseEvents};
7602 pos = clipPos(this, pos);
7603 return markText(this, pos, pos, realOpts, "bookmark");
7604 },
7605 findMarksAt: function(pos) {
7606 pos = clipPos(this, pos);
7607 var markers = [], spans = getLine(this, pos.line).markedSpans;
7608 if (spans) for (var i = 0; i < spans.length; ++i) {
7609 var span = spans[i];
7610 if ((span.from == null || span.from <= pos.ch) &&
7611 (span.to == null || span.to >= pos.ch))
7612 markers.push(span.marker.parent || span.marker);
7613 }
7614 return markers;
7615 },
7616 findMarks: function(from, to, filter) {
7617 from = clipPos(this, from); to = clipPos(this, to);
7618 var found = [], lineNo = from.line;
7619 this.iter(from.line, to.line + 1, function(line) {
7620 var spans = line.markedSpans;
7621 if (spans) for (var i = 0; i < spans.length; i++) {
7622 var span = spans[i];
7623 if (!(lineNo == from.line && from.ch > span.to ||
7624 span.from == null && lineNo != from.line||
7625 lineNo == to.line && span.from > to.ch) &&
7626 (!filter || filter(span.marker)))
7627 found.push(span.marker.parent || span.marker);
7628 }
7629 ++lineNo;
7630 });
7631 return found;
7632 },
7633 getAllMarks: function() {
7634 var markers = [];
7635 this.iter(function(line) {
7636 var sps = line.markedSpans;
7637 if (sps) for (var i = 0; i < sps.length; ++i)
7638 if (sps[i].from != null) markers.push(sps[i].marker);
7639 });
7640 return markers;
7641 },
7642
7643 posFromIndex: function(off) {
7644 var ch, lineNo = this.first;
7645 this.iter(function(line) {
7646 var sz = line.text.length + 1;
7647 if (sz > off) { ch = off; return true; }
7648 off -= sz;
7649 ++lineNo;
7650 });
7651 return clipPos(this, Pos(lineNo, ch));
7652 },
7653 indexFromPos: function (coords) {
7654 coords = clipPos(this, coords);
7655 var index = coords.ch;
7656 if (coords.line < this.first || coords.ch < 0) return 0;
7657 this.iter(this.first, coords.line, function (line) {
7658 index += line.text.length + 1;
7659 });
7660 return index;
7661 },
7662
7663 copy: function(copyHistory) {
7664 var doc = new Doc(getLines(this, this.first, this.first + this.size),
7665 this.modeOption, this.first, this.lineSep);
7666 doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
7667 doc.sel = this.sel;
7668 doc.extend = false;
7669 if (copyHistory) {
7670 doc.history.undoDepth = this.history.undoDepth;
7671 doc.setHistory(this.getHistory());
7672 }
7673 return doc;
7674 },
7675
7676 linkedDoc: function(options) {
7677 if (!options) options = {};
7678 var from = this.first, to = this.first + this.size;
7679 if (options.from != null && options.from > from) from = options.from;
7680 if (options.to != null && options.to < to) to = options.to;
7681 var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep);
7682 if (options.sharedHist) copy.history = this.history;
7683 (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
7684 copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
7685 copySharedMarkers(copy, findSharedMarkers(this));
7686 return copy;
7687 },
7688 unlinkDoc: function(other) {
7689 if (other instanceof CodeMirror) other = other.doc;
7690 if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
7691 var link = this.linked[i];
7692 if (link.doc != other) continue;
7693 this.linked.splice(i, 1);
7694 other.unlinkDoc(this);
7695 detachSharedMarkers(findSharedMarkers(this));
7696 break;
7697 }
7698 // If the histories were shared, split them again
7699 if (other.history == this.history) {
7700 var splitIds = [other.id];
7701 linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
7702 other.history = new History(null);
7703 other.history.done = copyHistoryArray(this.history.done, splitIds);
7704 other.history.undone = copyHistoryArray(this.history.undone, splitIds);
7705 }
7706 },
7707 iterLinkedDocs: function(f) {linkedDocs(this, f);},
7708
7709 getMode: function() {return this.mode;},
7710 getEditor: function() {return this.cm;},
7711
7712 splitLines: function(str) {
7713 if (this.lineSep) return str.split(this.lineSep);
7714 return splitLinesAuto(str);
7715 },
7716 lineSeparator: function() { return this.lineSep || "\n"; }
7717 });
7718
7719 // Public alias.
7720 Doc.prototype.eachLine = Doc.prototype.iter;
7721
7722 // Set up methods on CodeMirror's prototype to redirect to the editor's document.
7723 var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
7724 for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
7725 CodeMirror.prototype[prop] = (function(method) {
7726 return function() {return method.apply(this.doc, arguments);};
7727 })(Doc.prototype[prop]);
7728
7729 eventMixin(Doc);
7730
7731 // Call f for all linked documents.
4766 // Call f for all linked documents.
7732 function linkedDocs(doc, f, sharedHistOnly) {
4767 function linkedDocs(doc, f, sharedHistOnly) {
7733 function propagate(doc, skip, sharedHist) {
4768 function propagate(doc, skip, sharedHist) {
7734 if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
4769 if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
7735 var rel = doc.linked[i];
4770 var rel = doc.linked[i];
7736 if (rel.doc == skip) continue;
4771 if (rel.doc == skip) { continue }
7737 var shared = sharedHist && rel.sharedHist;
4772 var shared = sharedHist && rel.sharedHist;
7738 if (sharedHistOnly && !shared) continue;
4773 if (sharedHistOnly && !shared) { continue }
7739 f(rel.doc, shared);
4774 f(rel.doc, shared);
7740 propagate(rel.doc, doc, shared);
4775 propagate(rel.doc, doc, shared);
7741 }
4776 } }
7742 }
4777 }
7743 propagate(doc, null, true);
4778 propagate(doc, null, true);
7744 }
4779 }
7745
4780
7746 // Attach a document to an editor.
4781 // Attach a document to an editor.
7747 function attachDoc(cm, doc) {
4782 function attachDoc(cm, doc) {
7748 if (doc.cm) throw new Error("This document is already in use.");
4783 if (doc.cm) { throw new Error("This document is already in use.") }
7749 cm.doc = doc;
4784 cm.doc = doc;
7750 doc.cm = cm;
4785 doc.cm = cm;
7751 estimateLineHeights(cm);
4786 estimateLineHeights(cm);
7752 loadMode(cm);
4787 loadMode(cm);
7753 if (!cm.options.lineWrapping) findMaxLine(cm);
4788 setDirectionClass(cm);
4789 if (!cm.options.lineWrapping) { findMaxLine(cm); }
7754 cm.options.mode = doc.modeOption;
4790 cm.options.mode = doc.modeOption;
7755 regChange(cm);
4791 regChange(cm);
7756 }
4792 }
7757
4793
7758 // LINE UTILITIES
4794 function setDirectionClass(cm) {
7759
4795 (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
7760 // Find the line object corresponding to the given line number.
4796 }
7761 function getLine(doc, n) {
4797
7762 n -= doc.first;
4798 function directionChanged(cm) {
7763 if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
4799 runInOp(cm, function () {
7764 for (var chunk = doc; !chunk.lines;) {
4800 setDirectionClass(cm);
7765 for (var i = 0;; ++i) {
4801 regChange(cm);
7766 var child = chunk.children[i], sz = child.chunkSize();
7767 if (n < sz) { chunk = child; break; }
7768 n -= sz;
7769 }
7770 }
7771 return chunk.lines[n];
7772 }
7773
7774 // Get the part of a document between two positions, as an array of
7775 // strings.
7776 function getBetween(doc, start, end) {
7777 var out = [], n = start.line;
7778 doc.iter(start.line, end.line + 1, function(line) {
7779 var text = line.text;
7780 if (n == end.line) text = text.slice(0, end.ch);
7781 if (n == start.line) text = text.slice(start.ch);
7782 out.push(text);
7783 ++n;
7784 });
4802 });
7785 return out;
4803 }
7786 }
7787 // Get the lines between from and to, as array of strings.
7788 function getLines(doc, from, to) {
7789 var out = [];
7790 doc.iter(from, to, function(line) { out.push(line.text); });
7791 return out;
7792 }
7793
7794 // Update the height of a line, propagating the height change
7795 // upwards to parent nodes.
7796 function updateLineHeight(line, height) {
7797 var diff = height - line.height;
7798 if (diff) for (var n = line; n; n = n.parent) n.height += diff;
7799 }
7800
7801 // Given a line object, find its line number by walking up through
7802 // its parent links.
7803 function lineNo(line) {
7804 if (line.parent == null) return null;
7805 var cur = line.parent, no = indexOf(cur.lines, line);
7806 for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
7807 for (var i = 0;; ++i) {
7808 if (chunk.children[i] == cur) break;
7809 no += chunk.children[i].chunkSize();
7810 }
7811 }
7812 return no + cur.first;
7813 }
7814
7815 // Find the line at the given vertical position, using the height
7816 // information in the document tree.
7817 function lineAtHeight(chunk, h) {
7818 var n = chunk.first;
7819 outer: do {
7820 for (var i = 0; i < chunk.children.length; ++i) {
7821 var child = chunk.children[i], ch = child.height;
7822 if (h < ch) { chunk = child; continue outer; }
7823 h -= ch;
7824 n += child.chunkSize();
7825 }
7826 return n;
7827 } while (!chunk.lines);
7828 for (var i = 0; i < chunk.lines.length; ++i) {
7829 var line = chunk.lines[i], lh = line.height;
7830 if (h < lh) break;
7831 h -= lh;
7832 }
7833 return n + i;
7834 }
7835
7836
7837 // Find the height above the given line.
7838 function heightAtLine(lineObj) {
7839 lineObj = visualLine(lineObj);
7840
7841 var h = 0, chunk = lineObj.parent;
7842 for (var i = 0; i < chunk.lines.length; ++i) {
7843 var line = chunk.lines[i];
7844 if (line == lineObj) break;
7845 else h += line.height;
7846 }
7847 for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
7848 for (var i = 0; i < p.children.length; ++i) {
7849 var cur = p.children[i];
7850 if (cur == chunk) break;
7851 else h += cur.height;
7852 }
7853 }
7854 return h;
7855 }
7856
7857 // Get the bidi ordering for the given line (and cache it). Returns
7858 // false for lines that are fully left-to-right, and an array of
7859 // BidiSpan objects otherwise.
7860 function getOrder(line) {
7861 var order = line.order;
7862 if (order == null) order = line.order = bidiOrdering(line.text);
7863 return order;
7864 }
7865
7866 // HISTORY
7867
4804
7868 function History(startGen) {
4805 function History(startGen) {
7869 // Arrays of change events and selections. Doing something adds an
4806 // Arrays of change events and selections. Doing something adds an
@@ -7885,8 +4822,8 b''
7885 function historyChangeFromChange(doc, change) {
4822 function historyChangeFromChange(doc, change) {
7886 var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
4823 var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
7887 attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
4824 attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
7888 linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
4825 linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
7889 return histChange;
4826 return histChange
7890 }
4827 }
7891
4828
7892 // Pop all selection events off the end of a history array. Stop at
4829 // Pop all selection events off the end of a history array. Stop at
@@ -7894,8 +4831,8 b''
7894 function clearSelectionEvents(array) {
4831 function clearSelectionEvents(array) {
7895 while (array.length) {
4832 while (array.length) {
7896 var last = lst(array);
4833 var last = lst(array);
7897 if (last.ranges) array.pop();
4834 if (last.ranges) { array.pop(); }
7898 else break;
4835 else { break }
7899 }
4836 }
7900 }
4837 }
7901
4838
@@ -7904,30 +4841,31 b''
7904 function lastChangeEvent(hist, force) {
4841 function lastChangeEvent(hist, force) {
7905 if (force) {
4842 if (force) {
7906 clearSelectionEvents(hist.done);
4843 clearSelectionEvents(hist.done);
7907 return lst(hist.done);
4844 return lst(hist.done)
7908 } else if (hist.done.length && !lst(hist.done).ranges) {
4845 } else if (hist.done.length && !lst(hist.done).ranges) {
7909 return lst(hist.done);
4846 return lst(hist.done)
7910 } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
4847 } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
7911 hist.done.pop();
4848 hist.done.pop();
7912 return lst(hist.done);
4849 return lst(hist.done)
7913 }
4850 }
7914 }
4851 }
7915
4852
7916 // Register a change in the history. Merges changes that are within
4853 // Register a change in the history. Merges changes that are within
7917 // a single operation, ore are close together with an origin that
4854 // a single operation, or are close together with an origin that
7918 // allows merging (starting with "+") into a single event.
4855 // allows merging (starting with "+") into a single event.
7919 function addChangeToHistory(doc, change, selAfter, opId) {
4856 function addChangeToHistory(doc, change, selAfter, opId) {
7920 var hist = doc.history;
4857 var hist = doc.history;
7921 hist.undone.length = 0;
4858 hist.undone.length = 0;
7922 var time = +new Date, cur;
4859 var time = +new Date, cur;
4860 var last;
7923
4861
7924 if ((hist.lastOp == opId ||
4862 if ((hist.lastOp == opId ||
7925 hist.lastOrigin == change.origin && change.origin &&
4863 hist.lastOrigin == change.origin && change.origin &&
7926 ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
4864 ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||
7927 change.origin.charAt(0) == "*")) &&
4865 change.origin.charAt(0) == "*")) &&
7928 (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
4866 (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
7929 // Merge this change into the last event
4867 // Merge this change into the last event
7930 var last = lst(cur.changes);
4868 last = lst(cur.changes);
7931 if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
4869 if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
7932 // Optimized case for simple insertion -- don't want to add
4870 // Optimized case for simple insertion -- don't want to add
7933 // new changesets for every character typed
4871 // new changesets for every character typed
@@ -7940,13 +4878,13 b''
7940 // Can not be merged, start a new event.
4878 // Can not be merged, start a new event.
7941 var before = lst(hist.done);
4879 var before = lst(hist.done);
7942 if (!before || !before.ranges)
4880 if (!before || !before.ranges)
7943 pushSelectionToHistory(doc.sel, hist.done);
4881 { pushSelectionToHistory(doc.sel, hist.done); }
7944 cur = {changes: [historyChangeFromChange(doc, change)],
4882 cur = {changes: [historyChangeFromChange(doc, change)],
7945 generation: hist.generation};
4883 generation: hist.generation};
7946 hist.done.push(cur);
4884 hist.done.push(cur);
7947 while (hist.done.length > hist.undoDepth) {
4885 while (hist.done.length > hist.undoDepth) {
7948 hist.done.shift();
4886 hist.done.shift();
7949 if (!hist.done[0].ranges) hist.done.shift();
4887 if (!hist.done[0].ranges) { hist.done.shift(); }
7950 }
4888 }
7951 }
4889 }
7952 hist.done.push(selAfter);
4890 hist.done.push(selAfter);
@@ -7955,7 +4893,7 b''
7955 hist.lastOp = hist.lastSelOp = opId;
4893 hist.lastOp = hist.lastSelOp = opId;
7956 hist.lastOrigin = hist.lastSelOrigin = change.origin;
4894 hist.lastOrigin = hist.lastSelOrigin = change.origin;
7957
4895
7958 if (!last) signal(doc, "historyAdded");
4896 if (!last) { signal(doc, "historyAdded"); }
7959 }
4897 }
7960
4898
7961 function selectionEventCanBeMerged(doc, origin, prev, sel) {
4899 function selectionEventCanBeMerged(doc, origin, prev, sel) {
@@ -7964,7 +4902,7 b''
7964 ch == "+" &&
4902 ch == "+" &&
7965 prev.ranges.length == sel.ranges.length &&
4903 prev.ranges.length == sel.ranges.length &&
7966 prev.somethingSelected() == sel.somethingSelected() &&
4904 prev.somethingSelected() == sel.somethingSelected() &&
7967 new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
4905 new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
7968 }
4906 }
7969
4907
7970 // Called whenever the selection changes, sets the new selection as
4908 // Called whenever the selection changes, sets the new selection as
@@ -7982,21 +4920,21 b''
7982 (origin && hist.lastSelOrigin == origin &&
4920 (origin && hist.lastSelOrigin == origin &&
7983 (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
4921 (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
7984 selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
4922 selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
7985 hist.done[hist.done.length - 1] = sel;
4923 { hist.done[hist.done.length - 1] = sel; }
7986 else
4924 else
7987 pushSelectionToHistory(sel, hist.done);
4925 { pushSelectionToHistory(sel, hist.done); }
7988
4926
7989 hist.lastSelTime = +new Date;
4927 hist.lastSelTime = +new Date;
7990 hist.lastSelOrigin = origin;
4928 hist.lastSelOrigin = origin;
7991 hist.lastSelOp = opId;
4929 hist.lastSelOp = opId;
7992 if (options && options.clearRedo !== false)
4930 if (options && options.clearRedo !== false)
7993 clearSelectionEvents(hist.undone);
4931 { clearSelectionEvents(hist.undone); }
7994 }
4932 }
7995
4933
7996 function pushSelectionToHistory(sel, dest) {
4934 function pushSelectionToHistory(sel, dest) {
7997 var top = lst(dest);
4935 var top = lst(dest);
7998 if (!(top && top.ranges && top.equals(sel)))
4936 if (!(top && top.ranges && top.equals(sel)))
7999 dest.push(sel);
4937 { dest.push(sel); }
8000 }
4938 }
8001
4939
8002 // Used to store marked span information in the history.
4940 // Used to store marked span information in the history.
@@ -8004,7 +4942,7 b''
8004 var existing = change["spans_" + doc.id], n = 0;
4942 var existing = change["spans_" + doc.id], n = 0;
8005 doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
4943 doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
8006 if (line.markedSpans)
4944 if (line.markedSpans)
8007 (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
4945 { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
8008 ++n;
4946 ++n;
8009 });
4947 });
8010 }
4948 }
@@ -8012,46 +4950,549 b''
8012 // When un/re-doing restores text containing marked spans, those
4950 // When un/re-doing restores text containing marked spans, those
8013 // that have been explicitly cleared should not be restored.
4951 // that have been explicitly cleared should not be restored.
8014 function removeClearedSpans(spans) {
4952 function removeClearedSpans(spans) {
8015 if (!spans) return null;
4953 if (!spans) { return null }
8016 for (var i = 0, out; i < spans.length; ++i) {
4954 var out;
8017 if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
4955 for (var i = 0; i < spans.length; ++i) {
8018 else if (out) out.push(spans[i]);
4956 if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
8019 }
4957 else if (out) { out.push(spans[i]); }
8020 return !out ? spans : out.length ? out : null;
4958 }
4959 return !out ? spans : out.length ? out : null
8021 }
4960 }
8022
4961
8023 // Retrieve and filter the old marked spans stored in a change event.
4962 // Retrieve and filter the old marked spans stored in a change event.
8024 function getOldSpans(doc, change) {
4963 function getOldSpans(doc, change) {
8025 var found = change["spans_" + doc.id];
4964 var found = change["spans_" + doc.id];
8026 if (!found) return null;
4965 if (!found) { return null }
8027 for (var i = 0, nw = []; i < change.text.length; ++i)
4966 var nw = [];
8028 nw.push(removeClearedSpans(found[i]));
4967 for (var i = 0; i < change.text.length; ++i)
8029 return nw;
4968 { nw.push(removeClearedSpans(found[i])); }
4969 return nw
4970 }
4971
4972 // Used for un/re-doing changes from the history. Combines the
4973 // result of computing the existing spans with the set of spans that
4974 // existed in the history (so that deleting around a span and then
4975 // undoing brings back the span).
4976 function mergeOldSpans(doc, change) {
4977 var old = getOldSpans(doc, change);
4978 var stretched = stretchSpansOverChange(doc, change);
4979 if (!old) { return stretched }
4980 if (!stretched) { return old }
4981
4982 for (var i = 0; i < old.length; ++i) {
4983 var oldCur = old[i], stretchCur = stretched[i];
4984 if (oldCur && stretchCur) {
4985 spans: for (var j = 0; j < stretchCur.length; ++j) {
4986 var span = stretchCur[j];
4987 for (var k = 0; k < oldCur.length; ++k)
4988 { if (oldCur[k].marker == span.marker) { continue spans } }
4989 oldCur.push(span);
4990 }
4991 } else if (stretchCur) {
4992 old[i] = stretchCur;
4993 }
4994 }
4995 return old
8030 }
4996 }
8031
4997
8032 // Used both to provide a JSON-safe object in .getHistory, and, when
4998 // Used both to provide a JSON-safe object in .getHistory, and, when
8033 // detaching a document, to split the history in two
4999 // detaching a document, to split the history in two
8034 function copyHistoryArray(events, newGroup, instantiateSel) {
5000 function copyHistoryArray(events, newGroup, instantiateSel) {
8035 for (var i = 0, copy = []; i < events.length; ++i) {
5001 var copy = [];
5002 for (var i = 0; i < events.length; ++i) {
8036 var event = events[i];
5003 var event = events[i];
8037 if (event.ranges) {
5004 if (event.ranges) {
8038 copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
5005 copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
8039 continue;
5006 continue
8040 }
5007 }
8041 var changes = event.changes, newChanges = [];
5008 var changes = event.changes, newChanges = [];
8042 copy.push({changes: newChanges});
5009 copy.push({changes: newChanges});
8043 for (var j = 0; j < changes.length; ++j) {
5010 for (var j = 0; j < changes.length; ++j) {
8044 var change = changes[j], m;
5011 var change = changes[j], m = (void 0);
8045 newChanges.push({from: change.from, to: change.to, text: change.text});
5012 newChanges.push({from: change.from, to: change.to, text: change.text});
8046 if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
5013 if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
8047 if (indexOf(newGroup, Number(m[1])) > -1) {
5014 if (indexOf(newGroup, Number(m[1])) > -1) {
8048 lst(newChanges)[prop] = change[prop];
5015 lst(newChanges)[prop] = change[prop];
8049 delete change[prop];
5016 delete change[prop];
8050 }
5017 }
8051 }
5018 } } }
8052 }
5019 }
8053 }
5020 }
8054 return copy;
5021 return copy
5022 }
5023
5024 // The 'scroll' parameter given to many of these indicated whether
5025 // the new cursor position should be scrolled into view after
5026 // modifying the selection.
5027
5028 // If shift is held or the extend flag is set, extends a range to
5029 // include a given position (and optionally a second position).
5030 // Otherwise, simply returns the range between the given positions.
5031 // Used for cursor motion and such.
5032 function extendRange(range, head, other, extend) {
5033 if (extend) {
5034 var anchor = range.anchor;
5035 if (other) {
5036 var posBefore = cmp(head, anchor) < 0;
5037 if (posBefore != (cmp(other, anchor) < 0)) {
5038 anchor = head;
5039 head = other;
5040 } else if (posBefore != (cmp(head, other) < 0)) {
5041 head = other;
5042 }
5043 }
5044 return new Range(anchor, head)
5045 } else {
5046 return new Range(other || head, head)
5047 }
5048 }
5049
5050 // Extend the primary selection range, discard the rest.
5051 function extendSelection(doc, head, other, options, extend) {
5052 if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
5053 setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
5054 }
5055
5056 // Extend all selections (pos is an array of selections with length
5057 // equal the number of selections)
5058 function extendSelections(doc, heads, options) {
5059 var out = [];
5060 var extend = doc.cm && (doc.cm.display.shift || doc.extend);
5061 for (var i = 0; i < doc.sel.ranges.length; i++)
5062 { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
5063 var newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex);
5064 setSelection(doc, newSel, options);
5065 }
5066
5067 // Updates a single range in the selection.
5068 function replaceOneSelection(doc, i, range, options) {
5069 var ranges = doc.sel.ranges.slice(0);
5070 ranges[i] = range;
5071 setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options);
5072 }
5073
5074 // Reset the selection to a single range.
5075 function setSimpleSelection(doc, anchor, head, options) {
5076 setSelection(doc, simpleSelection(anchor, head), options);
5077 }
5078
5079 // Give beforeSelectionChange handlers a change to influence a
5080 // selection update.
5081 function filterSelectionChange(doc, sel, options) {
5082 var obj = {
5083 ranges: sel.ranges,
5084 update: function(ranges) {
5085 var this$1 = this;
5086
5087 this.ranges = [];
5088 for (var i = 0; i < ranges.length; i++)
5089 { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
5090 clipPos(doc, ranges[i].head)); }
5091 },
5092 origin: options && options.origin
5093 };
5094 signal(doc, "beforeSelectionChange", doc, obj);
5095 if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
5096 if (obj.ranges != sel.ranges) { return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) }
5097 else { return sel }
5098 }
5099
5100 function setSelectionReplaceHistory(doc, sel, options) {
5101 var done = doc.history.done, last = lst(done);
5102 if (last && last.ranges) {
5103 done[done.length - 1] = sel;
5104 setSelectionNoUndo(doc, sel, options);
5105 } else {
5106 setSelection(doc, sel, options);
5107 }
5108 }
5109
5110 // Set a new selection.
5111 function setSelection(doc, sel, options) {
5112 setSelectionNoUndo(doc, sel, options);
5113 addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
5114 }
5115
5116 function setSelectionNoUndo(doc, sel, options) {
5117 if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
5118 { sel = filterSelectionChange(doc, sel, options); }
5119
5120 var bias = options && options.bias ||
5121 (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
5122 setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
5123
5124 if (!(options && options.scroll === false) && doc.cm)
5125 { ensureCursorVisible(doc.cm); }
5126 }
5127
5128 function setSelectionInner(doc, sel) {
5129 if (sel.equals(doc.sel)) { return }
5130
5131 doc.sel = sel;
5132
5133 if (doc.cm) {
5134 doc.cm.curOp.updateInput = 1;
5135 doc.cm.curOp.selectionChanged = true;
5136 signalCursorActivity(doc.cm);
5137 }
5138 signalLater(doc, "cursorActivity", doc);
5139 }
5140
5141 // Verify that the selection does not partially select any atomic
5142 // marked ranges.
5143 function reCheckSelection(doc) {
5144 setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
5145 }
5146
5147 // Return a selection that does not partially select any atomic
5148 // ranges.
5149 function skipAtomicInSelection(doc, sel, bias, mayClear) {
5150 var out;
5151 for (var i = 0; i < sel.ranges.length; i++) {
5152 var range = sel.ranges[i];
5153 var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
5154 var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
5155 var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
5156 if (out || newAnchor != range.anchor || newHead != range.head) {
5157 if (!out) { out = sel.ranges.slice(0, i); }
5158 out[i] = new Range(newAnchor, newHead);
5159 }
5160 }
5161 return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel
5162 }
5163
5164 function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
5165 var line = getLine(doc, pos.line);
5166 if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
5167 var sp = line.markedSpans[i], m = sp.marker;
5168
5169 // Determine if we should prevent the cursor being placed to the left/right of an atomic marker
5170 // Historically this was determined using the inclusiveLeft/Right option, but the new way to control it
5171 // is with selectLeft/Right
5172 var preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft;
5173 var preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight;
5174
5175 if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
5176 (sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
5177 if (mayClear) {
5178 signal(m, "beforeCursorEnter");
5179 if (m.explicitlyCleared) {
5180 if (!line.markedSpans) { break }
5181 else {--i; continue}
5182 }
5183 }
5184 if (!m.atomic) { continue }
5185
5186 if (oldPos) {
5187 var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
5188 if (dir < 0 ? preventCursorRight : preventCursorLeft)
5189 { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
5190 if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
5191 { return skipAtomicInner(doc, near, pos, dir, mayClear) }
5192 }
5193
5194 var far = m.find(dir < 0 ? -1 : 1);
5195 if (dir < 0 ? preventCursorLeft : preventCursorRight)
5196 { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
5197 return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
5198 }
5199 } }
5200 return pos
5201 }
5202
5203 // Ensure a given position is not inside an atomic range.
5204 function skipAtomic(doc, pos, oldPos, bias, mayClear) {
5205 var dir = bias || 1;
5206 var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
5207 (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
5208 skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
5209 (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
5210 if (!found) {
5211 doc.cantEdit = true;
5212 return Pos(doc.first, 0)
5213 }
5214 return found
5215 }
5216
5217 function movePos(doc, pos, dir, line) {
5218 if (dir < 0 && pos.ch == 0) {
5219 if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
5220 else { return null }
5221 } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
5222 if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
5223 else { return null }
5224 } else {
5225 return new Pos(pos.line, pos.ch + dir)
5226 }
5227 }
5228
5229 function selectAll(cm) {
5230 cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
5231 }
5232
5233 // UPDATING
5234
5235 // Allow "beforeChange" event handlers to influence a change
5236 function filterChange(doc, change, update) {
5237 var obj = {
5238 canceled: false,
5239 from: change.from,
5240 to: change.to,
5241 text: change.text,
5242 origin: change.origin,
5243 cancel: function () { return obj.canceled = true; }
5244 };
5245 if (update) { obj.update = function (from, to, text, origin) {
5246 if (from) { obj.from = clipPos(doc, from); }
5247 if (to) { obj.to = clipPos(doc, to); }
5248 if (text) { obj.text = text; }
5249 if (origin !== undefined) { obj.origin = origin; }
5250 }; }
5251 signal(doc, "beforeChange", doc, obj);
5252 if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
5253
5254 if (obj.canceled) {
5255 if (doc.cm) { doc.cm.curOp.updateInput = 2; }
5256 return null
5257 }
5258 return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
5259 }
5260
5261 // Apply a change to a document, and add it to the document's
5262 // history, and propagating it to all linked documents.
5263 function makeChange(doc, change, ignoreReadOnly) {
5264 if (doc.cm) {
5265 if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
5266 if (doc.cm.state.suppressEdits) { return }
5267 }
5268
5269 if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
5270 change = filterChange(doc, change, true);
5271 if (!change) { return }
5272 }
5273
5274 // Possibly split or suppress the update based on the presence
5275 // of read-only spans in its range.
5276 var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
5277 if (split) {
5278 for (var i = split.length - 1; i >= 0; --i)
5279 { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
5280 } else {
5281 makeChangeInner(doc, change);
5282 }
5283 }
5284
5285 function makeChangeInner(doc, change) {
5286 if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
5287 var selAfter = computeSelAfterChange(doc, change);
5288 addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
5289
5290 makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
5291 var rebased = [];
5292
5293 linkedDocs(doc, function (doc, sharedHist) {
5294 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
5295 rebaseHist(doc.history, change);
5296 rebased.push(doc.history);
5297 }
5298 makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
5299 });
5300 }
5301
5302 // Revert a change stored in a document's history.
5303 function makeChangeFromHistory(doc, type, allowSelectionOnly) {
5304 var suppress = doc.cm && doc.cm.state.suppressEdits;
5305 if (suppress && !allowSelectionOnly) { return }
5306
5307 var hist = doc.history, event, selAfter = doc.sel;
5308 var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
5309
5310 // Verify that there is a useable event (so that ctrl-z won't
5311 // needlessly clear selection events)
5312 var i = 0;
5313 for (; i < source.length; i++) {
5314 event = source[i];
5315 if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
5316 { break }
5317 }
5318 if (i == source.length) { return }
5319 hist.lastOrigin = hist.lastSelOrigin = null;
5320
5321 for (;;) {
5322 event = source.pop();
5323 if (event.ranges) {
5324 pushSelectionToHistory(event, dest);
5325 if (allowSelectionOnly && !event.equals(doc.sel)) {
5326 setSelection(doc, event, {clearRedo: false});
5327 return
5328 }
5329 selAfter = event;
5330 } else if (suppress) {
5331 source.push(event);
5332 return
5333 } else { break }
5334 }
5335
5336 // Build up a reverse change object to add to the opposite history
5337 // stack (redo when undoing, and vice versa).
5338 var antiChanges = [];
5339 pushSelectionToHistory(selAfter, dest);
5340 dest.push({changes: antiChanges, generation: hist.generation});
5341 hist.generation = event.generation || ++hist.maxGeneration;
5342
5343 var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
5344
5345 var loop = function ( i ) {
5346 var change = event.changes[i];
5347 change.origin = type;
5348 if (filter && !filterChange(doc, change, false)) {
5349 source.length = 0;
5350 return {}
5351 }
5352
5353 antiChanges.push(historyChangeFromChange(doc, change));
5354
5355 var after = i ? computeSelAfterChange(doc, change) : lst(source);
5356 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
5357 if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
5358 var rebased = [];
5359
5360 // Propagate to the linked documents
5361 linkedDocs(doc, function (doc, sharedHist) {
5362 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
5363 rebaseHist(doc.history, change);
5364 rebased.push(doc.history);
5365 }
5366 makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
5367 });
5368 };
5369
5370 for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
5371 var returned = loop( i$1 );
5372
5373 if ( returned ) return returned.v;
5374 }
5375 }
5376
5377 // Sub-views need their line numbers shifted when text is added
5378 // above or below them in the parent document.
5379 function shiftDoc(doc, distance) {
5380 if (distance == 0) { return }
5381 doc.first += distance;
5382 doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
5383 Pos(range.anchor.line + distance, range.anchor.ch),
5384 Pos(range.head.line + distance, range.head.ch)
5385 ); }), doc.sel.primIndex);
5386 if (doc.cm) {
5387 regChange(doc.cm, doc.first, doc.first - distance, distance);
5388 for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
5389 { regLineChange(doc.cm, l, "gutter"); }
5390 }
5391 }
5392
5393 // More lower-level change function, handling only a single document
5394 // (not linked ones).
5395 function makeChangeSingleDoc(doc, change, selAfter, spans) {
5396 if (doc.cm && !doc.cm.curOp)
5397 { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
5398
5399 if (change.to.line < doc.first) {
5400 shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
5401 return
5402 }
5403 if (change.from.line > doc.lastLine()) { return }
5404
5405 // Clip the change to the size of this doc
5406 if (change.from.line < doc.first) {
5407 var shift = change.text.length - 1 - (doc.first - change.from.line);
5408 shiftDoc(doc, shift);
5409 change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
5410 text: [lst(change.text)], origin: change.origin};
5411 }
5412 var last = doc.lastLine();
5413 if (change.to.line > last) {
5414 change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
5415 text: [change.text[0]], origin: change.origin};
5416 }
5417
5418 change.removed = getBetween(doc, change.from, change.to);
5419
5420 if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
5421 if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
5422 else { updateDoc(doc, change, spans); }
5423 setSelectionNoUndo(doc, selAfter, sel_dontScroll);
5424
5425 if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0)))
5426 { doc.cantEdit = false; }
5427 }
5428
5429 // Handle the interaction of a change to a document with the editor
5430 // that this document is part of.
5431 function makeChangeSingleDocInEditor(cm, change, spans) {
5432 var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
5433
5434 var recomputeMaxLength = false, checkWidthStart = from.line;
5435 if (!cm.options.lineWrapping) {
5436 checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
5437 doc.iter(checkWidthStart, to.line + 1, function (line) {
5438 if (line == display.maxLine) {
5439 recomputeMaxLength = true;
5440 return true
5441 }
5442 });
5443 }
5444
5445 if (doc.sel.contains(change.from, change.to) > -1)
5446 { signalCursorActivity(cm); }
5447
5448 updateDoc(doc, change, spans, estimateHeight(cm));
5449
5450 if (!cm.options.lineWrapping) {
5451 doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
5452 var len = lineLength(line);
5453 if (len > display.maxLineLength) {
5454 display.maxLine = line;
5455 display.maxLineLength = len;
5456 display.maxLineChanged = true;
5457 recomputeMaxLength = false;
5458 }
5459 });
5460 if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
5461 }
5462
5463 retreatFrontier(doc, from.line);
5464 startWorker(cm, 400);
5465
5466 var lendiff = change.text.length - (to.line - from.line) - 1;
5467 // Remember that these lines changed, for updating the display
5468 if (change.full)
5469 { regChange(cm); }
5470 else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
5471 { regLineChange(cm, from.line, "text"); }
5472 else
5473 { regChange(cm, from.line, to.line + 1, lendiff); }
5474
5475 var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
5476 if (changeHandler || changesHandler) {
5477 var obj = {
5478 from: from, to: to,
5479 text: change.text,
5480 removed: change.removed,
5481 origin: change.origin
5482 };
5483 if (changeHandler) { signalLater(cm, "change", cm, obj); }
5484 if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
5485 }
5486 cm.display.selForContextMenu = null;
5487 }
5488
5489 function replaceRange(doc, code, from, to, origin) {
5490 var assign;
5491
5492 if (!to) { to = from; }
5493 if (cmp(to, from) < 0) { (assign = [to, from], from = assign[0], to = assign[1]); }
5494 if (typeof code == "string") { code = doc.splitLines(code); }
5495 makeChange(doc, {from: from, to: to, text: code, origin: origin});
8055 }
5496 }
8056
5497
8057 // Rebasing/resetting history to deal with externally-sourced changes
5498 // Rebasing/resetting history to deal with externally-sourced changes
@@ -8081,16 +5522,16 b''
8081 rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
5522 rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
8082 rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
5523 rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
8083 }
5524 }
8084 continue;
5525 continue
8085 }
5526 }
8086 for (var j = 0; j < sub.changes.length; ++j) {
5527 for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
8087 var cur = sub.changes[j];
5528 var cur = sub.changes[j$1];
8088 if (to < cur.from.line) {
5529 if (to < cur.from.line) {
8089 cur.from = Pos(cur.from.line + diff, cur.from.ch);
5530 cur.from = Pos(cur.from.line + diff, cur.from.ch);
8090 cur.to = Pos(cur.to.line + diff, cur.to.ch);
5531 cur.to = Pos(cur.to.line + diff, cur.to.ch);
8091 } else if (from <= cur.to.line) {
5532 } else if (from <= cur.to.line) {
8092 ok = false;
5533 ok = false;
8093 break;
5534 break
8094 }
5535 }
8095 }
5536 }
8096 if (!ok) {
5537 if (!ok) {
@@ -8106,368 +5547,1105 b''
8106 rebaseHistArray(hist.undone, from, to, diff);
5547 rebaseHistArray(hist.undone, from, to, diff);
8107 }
5548 }
8108
5549
8109 // EVENT UTILITIES
5550 // Utility for applying a change to a line by handle or number,
8110
5551 // returning the number and optionally registering the line as
8111 // Due to the fact that we still support jurassic IE versions, some
5552 // changed.
8112 // compatibility wrappers are needed.
5553 function changeLine(doc, handle, changeType, op) {
8113
5554 var no = handle, line = handle;
8114 var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
5555 if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
8115 if (e.preventDefault) e.preventDefault();
5556 else { no = lineNo(handle); }
8116 else e.returnValue = false;
5557 if (no == null) { return null }
8117 };
5558 if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
8118 var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
5559 return line
8119 if (e.stopPropagation) e.stopPropagation();
5560 }
8120 else e.cancelBubble = true;
5561
8121 };
5562 // The document is represented as a BTree consisting of leaves, with
8122 function e_defaultPrevented(e) {
5563 // chunk of lines in them, and branches, with up to ten leaves or
8123 return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
5564 // other branch nodes below them. The top node is always a branch
8124 }
5565 // node, and is the document object itself (meaning it has
8125 var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
5566 // additional methods and properties).
8126
5567 //
8127 function e_target(e) {return e.target || e.srcElement;}
5568 // All nodes have parent links. The tree is used both to go from
8128 function e_button(e) {
5569 // line numbers to line objects, and to go from objects to numbers.
8129 var b = e.which;
5570 // It also indexes by height, and is used to convert between height
8130 if (b == null) {
5571 // and line object, and to find the total height of the document.
8131 if (e.button & 1) b = 1;
5572 //
8132 else if (e.button & 2) b = 3;
5573 // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
8133 else if (e.button & 4) b = 2;
5574
8134 }
5575 function LeafChunk(lines) {
8135 if (mac && e.ctrlKey && b == 1) b = 3;
5576 var this$1 = this;
8136 return b;
5577
8137 }
5578 this.lines = lines;
8138
5579 this.parent = null;
8139 // EVENT HANDLING
5580 var height = 0;
8140
5581 for (var i = 0; i < lines.length; ++i) {
8141 // Lightweight event framework. on/off also work on DOM nodes,
5582 lines[i].parent = this$1;
8142 // registering native DOM handlers.
5583 height += lines[i].height;
8143
5584 }
8144 var on = CodeMirror.on = function(emitter, type, f) {
5585 this.height = height;
8145 if (emitter.addEventListener)
5586 }
8146 emitter.addEventListener(type, f, false);
5587
8147 else if (emitter.attachEvent)
5588 LeafChunk.prototype = {
8148 emitter.attachEvent("on" + type, f);
5589 chunkSize: function() { return this.lines.length },
8149 else {
5590
8150 var map = emitter._handlers || (emitter._handlers = {});
5591 // Remove the n lines at offset 'at'.
8151 var arr = map[type] || (map[type] = []);
5592 removeInner: function(at, n) {
8152 arr.push(f);
5593 var this$1 = this;
8153 }
5594
8154 };
5595 for (var i = at, e = at + n; i < e; ++i) {
8155
5596 var line = this$1.lines[i];
8156 var noHandlers = []
5597 this$1.height -= line.height;
8157 function getHandlers(emitter, type, copy) {
5598 cleanUpLine(line);
8158 var arr = emitter._handlers && emitter._handlers[type]
5599 signalLater(line, "delete");
8159 if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
5600 }
8160 else return arr || noHandlers
5601 this.lines.splice(at, n);
8161 }
5602 },
8162
5603
8163 var off = CodeMirror.off = function(emitter, type, f) {
5604 // Helper used to collapse a small branch into a single leaf.
8164 if (emitter.removeEventListener)
5605 collapse: function(lines) {
8165 emitter.removeEventListener(type, f, false);
5606 lines.push.apply(lines, this.lines);
8166 else if (emitter.detachEvent)
5607 },
8167 emitter.detachEvent("on" + type, f);
5608
8168 else {
5609 // Insert the given array of lines at offset 'at', count them as
8169 var handlers = getHandlers(emitter, type, false)
5610 // having the given height.
8170 for (var i = 0; i < handlers.length; ++i)
5611 insertInner: function(at, lines, height) {
8171 if (handlers[i] == f) { handlers.splice(i, 1); break; }
5612 var this$1 = this;
8172 }
5613
8173 };
5614 this.height += height;
8174
5615 this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
8175 var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
5616 for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }
8176 var handlers = getHandlers(emitter, type, true)
5617 },
8177 if (!handlers.length) return;
5618
8178 var args = Array.prototype.slice.call(arguments, 2);
5619 // Used to iterate over a part of the tree.
8179 for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
5620 iterN: function(at, n, op) {
8180 };
5621 var this$1 = this;
8181
5622
8182 var orphanDelayedCallbacks = null;
5623 for (var e = at + n; at < e; ++at)
8183
5624 { if (op(this$1.lines[at])) { return true } }
8184 // Often, we want to signal events at a point where we are in the
5625 }
8185 // middle of some work, but don't want the handler to start calling
5626 };
8186 // other methods on the editor, which might be in an inconsistent
5627
8187 // state or simply not expect any other events to happen.
5628 function BranchChunk(children) {
8188 // signalLater looks whether there are any handlers, and schedules
5629 var this$1 = this;
8189 // them to be executed when the last operation ends, or, if no
5630
8190 // operation is active, when a timeout fires.
5631 this.children = children;
8191 function signalLater(emitter, type /*, values...*/) {
5632 var size = 0, height = 0;
8192 var arr = getHandlers(emitter, type, false)
5633 for (var i = 0; i < children.length; ++i) {
8193 if (!arr.length) return;
5634 var ch = children[i];
8194 var args = Array.prototype.slice.call(arguments, 2), list;
5635 size += ch.chunkSize(); height += ch.height;
8195 if (operationGroup) {
5636 ch.parent = this$1;
8196 list = operationGroup.delayedCallbacks;
5637 }
8197 } else if (orphanDelayedCallbacks) {
5638 this.size = size;
8198 list = orphanDelayedCallbacks;
5639 this.height = height;
5640 this.parent = null;
5641 }
5642
5643 BranchChunk.prototype = {
5644 chunkSize: function() { return this.size },
5645
5646 removeInner: function(at, n) {
5647 var this$1 = this;
5648
5649 this.size -= n;
5650 for (var i = 0; i < this.children.length; ++i) {
5651 var child = this$1.children[i], sz = child.chunkSize();
5652 if (at < sz) {
5653 var rm = Math.min(n, sz - at), oldHeight = child.height;
5654 child.removeInner(at, rm);
5655 this$1.height -= oldHeight - child.height;
5656 if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }
5657 if ((n -= rm) == 0) { break }
5658 at = 0;
5659 } else { at -= sz; }
5660 }
5661 // If the result is smaller than 25 lines, ensure that it is a
5662 // single leaf node.
5663 if (this.size - n < 25 &&
5664 (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
5665 var lines = [];
5666 this.collapse(lines);
5667 this.children = [new LeafChunk(lines)];
5668 this.children[0].parent = this;
5669 }
5670 },
5671
5672 collapse: function(lines) {
5673 var this$1 = this;
5674
5675 for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }
5676 },
5677
5678 insertInner: function(at, lines, height) {
5679 var this$1 = this;
5680
5681 this.size += lines.length;
5682 this.height += height;
5683 for (var i = 0; i < this.children.length; ++i) {
5684 var child = this$1.children[i], sz = child.chunkSize();
5685 if (at <= sz) {
5686 child.insertInner(at, lines, height);
5687 if (child.lines && child.lines.length > 50) {
5688 // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
5689 // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
5690 var remaining = child.lines.length % 25 + 25;
5691 for (var pos = remaining; pos < child.lines.length;) {
5692 var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
5693 child.height -= leaf.height;
5694 this$1.children.splice(++i, 0, leaf);
5695 leaf.parent = this$1;
5696 }
5697 child.lines = child.lines.slice(0, remaining);
5698 this$1.maybeSpill();
5699 }
5700 break
5701 }
5702 at -= sz;
5703 }
5704 },
5705
5706 // When a node has grown, check whether it should be split.
5707 maybeSpill: function() {
5708 if (this.children.length <= 10) { return }
5709 var me = this;
5710 do {
5711 var spilled = me.children.splice(me.children.length - 5, 5);
5712 var sibling = new BranchChunk(spilled);
5713 if (!me.parent) { // Become the parent node
5714 var copy = new BranchChunk(me.children);
5715 copy.parent = me;
5716 me.children = [copy, sibling];
5717 me = copy;
8199 } else {
5718 } else {
8200 list = orphanDelayedCallbacks = [];
5719 me.size -= sibling.size;
8201 setTimeout(fireOrphanDelayed, 0);
5720 me.height -= sibling.height;
8202 }
5721 var myIndex = indexOf(me.parent.children, me);
8203 function bnd(f) {return function(){f.apply(null, args);};};
5722 me.parent.children.splice(myIndex + 1, 0, sibling);
8204 for (var i = 0; i < arr.length; ++i)
5723 }
8205 list.push(bnd(arr[i]));
5724 sibling.parent = me.parent;
8206 }
5725 } while (me.children.length > 10)
8207
5726 me.parent.maybeSpill();
8208 function fireOrphanDelayed() {
5727 },
8209 var delayed = orphanDelayedCallbacks;
5728
8210 orphanDelayedCallbacks = null;
5729 iterN: function(at, n, op) {
8211 for (var i = 0; i < delayed.length; ++i) delayed[i]();
5730 var this$1 = this;
8212 }
5731
8213
5732 for (var i = 0; i < this.children.length; ++i) {
8214 // The DOM events that CodeMirror handles can be overridden by
5733 var child = this$1.children[i], sz = child.chunkSize();
8215 // registering a (non-DOM) handler on the editor for the event name,
5734 if (at < sz) {
8216 // and preventDefault-ing the event in that handler.
5735 var used = Math.min(n, sz - at);
8217 function signalDOMEvent(cm, e, override) {
5736 if (child.iterN(at, used, op)) { return true }
8218 if (typeof e == "string")
5737 if ((n -= used) == 0) { break }
8219 e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};
5738 at = 0;
8220 signal(cm, override || e.type, cm, e);
5739 } else { at -= sz; }
8221 return e_defaultPrevented(e) || e.codemirrorIgnore;
5740 }
8222 }
5741 }
8223
5742 };
8224 function signalCursorActivity(cm) {
5743
8225 var arr = cm._handlers && cm._handlers.cursorActivity;
5744 // Line widgets are block elements displayed above or below a line.
8226 if (!arr) return;
5745
8227 var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
5746 var LineWidget = function(doc, node, options) {
8228 for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
5747 var this$1 = this;
8229 set.push(arr[i]);
5748
8230 }
5749 if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
8231
5750 { this$1[opt] = options[opt]; } } }
8232 function hasHandler(emitter, type) {
5751 this.doc = doc;
8233 return getHandlers(emitter, type).length > 0
5752 this.node = node;
8234 }
5753 };
8235
5754
8236 // Add on and off methods to a constructor's prototype, to make
5755 LineWidget.prototype.clear = function () {
8237 // registering events on such objects more convenient.
5756 var this$1 = this;
8238 function eventMixin(ctor) {
5757
8239 ctor.prototype.on = function(type, f) {on(this, type, f);};
5758 var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
8240 ctor.prototype.off = function(type, f) {off(this, type, f);};
5759 if (no == null || !ws) { return }
8241 }
5760 for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }
8242
5761 if (!ws.length) { line.widgets = null; }
8243 // MISC UTILITIES
5762 var height = widgetHeight(this);
8244
5763 updateLineHeight(line, Math.max(0, line.height - height));
8245 // Number of pixels added to scroller and sizer to hide scrollbar
5764 if (cm) {
8246 var scrollerGap = 30;
5765 runInOp(cm, function () {
8247
5766 adjustScrollWhenAboveVisible(cm, line, -height);
8248 // Returned or thrown by various protocols to signal 'I'm not
5767 regLineChange(cm, no, "widget");
8249 // handling this'.
5768 });
8250 var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
5769 signalLater(cm, "lineWidgetCleared", cm, this, no);
8251
5770 }
8252 // Reused option objects for setSelection & friends
5771 };
8253 var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
5772
8254
5773 LineWidget.prototype.changed = function () {
8255 function Delayed() {this.id = null;}
5774 var this$1 = this;
8256 Delayed.prototype.set = function(ms, f) {
5775
8257 clearTimeout(this.id);
5776 var oldH = this.height, cm = this.doc.cm, line = this.line;
8258 this.id = setTimeout(f, ms);
5777 this.height = null;
8259 };
5778 var diff = widgetHeight(this) - oldH;
8260
5779 if (!diff) { return }
8261 // Counts the column offset in a string, taking tabs into account.
5780 if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); }
8262 // Used mostly to find indentation.
5781 if (cm) {
8263 var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
5782 runInOp(cm, function () {
8264 if (end == null) {
5783 cm.curOp.forceUpdate = true;
8265 end = string.search(/[^\s\u00a0]/);
5784 adjustScrollWhenAboveVisible(cm, line, diff);
8266 if (end == -1) end = string.length;
5785 signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
8267 }
5786 });
8268 for (var i = startIndex || 0, n = startValue || 0;;) {
5787 }
8269 var nextTab = string.indexOf("\t", i);
5788 };
8270 if (nextTab < 0 || nextTab >= end)
5789 eventMixin(LineWidget);
8271 return n + (end - i);
5790
8272 n += nextTab - i;
5791 function adjustScrollWhenAboveVisible(cm, line, diff) {
8273 n += tabSize - (n % tabSize);
5792 if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
8274 i = nextTab + 1;
5793 { addToScrollTop(cm, diff); }
8275 }
5794 }
8276 };
5795
8277
5796 function addLineWidget(doc, handle, node, options) {
8278 // The inverse of countColumn -- find the offset that corresponds to
5797 var widget = new LineWidget(doc, node, options);
8279 // a particular column.
5798 var cm = doc.cm;
8280 var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) {
5799 if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
8281 for (var pos = 0, col = 0;;) {
5800 changeLine(doc, handle, "widget", function (line) {
8282 var nextTab = string.indexOf("\t", pos);
5801 var widgets = line.widgets || (line.widgets = []);
8283 if (nextTab == -1) nextTab = string.length;
5802 if (widget.insertAt == null) { widgets.push(widget); }
8284 var skipped = nextTab - pos;
5803 else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
8285 if (nextTab == string.length || col + skipped >= goal)
5804 widget.line = line;
8286 return pos + Math.min(skipped, goal - col);
5805 if (cm && !lineIsHidden(doc, line)) {
8287 col += nextTab - pos;
5806 var aboveVisible = heightAtLine(line) < doc.scrollTop;
8288 col += tabSize - (col % tabSize);
5807 updateLineHeight(line, line.height + widgetHeight(widget));
8289 pos = nextTab + 1;
5808 if (aboveVisible) { addToScrollTop(cm, widget.height); }
8290 if (col >= goal) return pos;
5809 cm.curOp.forceUpdate = true;
8291 }
5810 }
8292 }
5811 return true
8293
5812 });
8294 var spaceStrs = [""];
5813 if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)); }
8295 function spaceStr(n) {
5814 return widget
8296 while (spaceStrs.length <= n)
5815 }
8297 spaceStrs.push(lst(spaceStrs) + " ");
5816
8298 return spaceStrs[n];
5817 // TEXTMARKERS
8299 }
5818
8300
5819 // Created with markText and setBookmark methods. A TextMarker is a
8301 function lst(arr) { return arr[arr.length-1]; }
5820 // handle that can be used to clear or find a marked position in the
8302
5821 // document. Line objects hold arrays (markedSpans) containing
8303 var selectInput = function(node) { node.select(); };
5822 // {from, to, marker} object pointing to such marker objects, and
8304 if (ios) // Mobile Safari apparently has a bug where select() is broken.
5823 // indicating that such a marker is present on that line. Multiple
8305 selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
5824 // lines may point to the same marker when it spans across lines.
8306 else if (ie) // Suppress mysterious IE10 errors
5825 // The spans will have null for their from/to properties when the
8307 selectInput = function(node) { try { node.select(); } catch(_e) {} };
5826 // marker continues beyond the start/end of the line. Markers have
8308
5827 // links back to the lines they currently touch.
8309 function indexOf(array, elt) {
5828
8310 for (var i = 0; i < array.length; ++i)
5829 // Collapsed markers have unique ids, in order to be able to order
8311 if (array[i] == elt) return i;
5830 // them, which is needed for uniquely determining an outer marker
8312 return -1;
5831 // when they overlap (they may nest, but not partially overlap).
8313 }
5832 var nextMarkerId = 0;
8314 function map(array, f) {
5833
5834 var TextMarker = function(doc, type) {
5835 this.lines = [];
5836 this.type = type;
5837 this.doc = doc;
5838 this.id = ++nextMarkerId;
5839 };
5840
5841 // Clear the marker.
5842 TextMarker.prototype.clear = function () {
5843 var this$1 = this;
5844
5845 if (this.explicitlyCleared) { return }
5846 var cm = this.doc.cm, withOp = cm && !cm.curOp;
5847 if (withOp) { startOperation(cm); }
5848 if (hasHandler(this, "clear")) {
5849 var found = this.find();
5850 if (found) { signalLater(this, "clear", found.from, found.to); }
5851 }
5852 var min = null, max = null;
5853 for (var i = 0; i < this.lines.length; ++i) {
5854 var line = this$1.lines[i];
5855 var span = getMarkedSpanFor(line.markedSpans, this$1);
5856 if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); }
5857 else if (cm) {
5858 if (span.to != null) { max = lineNo(line); }
5859 if (span.from != null) { min = lineNo(line); }
5860 }
5861 line.markedSpans = removeMarkedSpan(line.markedSpans, span);
5862 if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
5863 { updateLineHeight(line, textHeight(cm.display)); }
5864 }
5865 if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
5866 var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);
5867 if (len > cm.display.maxLineLength) {
5868 cm.display.maxLine = visual;
5869 cm.display.maxLineLength = len;
5870 cm.display.maxLineChanged = true;
5871 }
5872 } }
5873
5874 if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
5875 this.lines.length = 0;
5876 this.explicitlyCleared = true;
5877 if (this.atomic && this.doc.cantEdit) {
5878 this.doc.cantEdit = false;
5879 if (cm) { reCheckSelection(cm.doc); }
5880 }
5881 if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
5882 if (withOp) { endOperation(cm); }
5883 if (this.parent) { this.parent.clear(); }
5884 };
5885
5886 // Find the position of the marker in the document. Returns a {from,
5887 // to} object by default. Side can be passed to get a specific side
5888 // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
5889 // Pos objects returned contain a line object, rather than a line
5890 // number (used to prevent looking up the same line twice).
5891 TextMarker.prototype.find = function (side, lineObj) {
5892 var this$1 = this;
5893
5894 if (side == null && this.type == "bookmark") { side = 1; }
5895 var from, to;
5896 for (var i = 0; i < this.lines.length; ++i) {
5897 var line = this$1.lines[i];
5898 var span = getMarkedSpanFor(line.markedSpans, this$1);
5899 if (span.from != null) {
5900 from = Pos(lineObj ? line : lineNo(line), span.from);
5901 if (side == -1) { return from }
5902 }
5903 if (span.to != null) {
5904 to = Pos(lineObj ? line : lineNo(line), span.to);
5905 if (side == 1) { return to }
5906 }
5907 }
5908 return from && {from: from, to: to}
5909 };
5910
5911 // Signals that the marker's widget changed, and surrounding layout
5912 // should be recomputed.
5913 TextMarker.prototype.changed = function () {
5914 var this$1 = this;
5915
5916 var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
5917 if (!pos || !cm) { return }
5918 runInOp(cm, function () {
5919 var line = pos.line, lineN = lineNo(pos.line);
5920 var view = findViewForLine(cm, lineN);
5921 if (view) {
5922 clearLineMeasurementCacheFor(view);
5923 cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
5924 }
5925 cm.curOp.updateMaxLine = true;
5926 if (!lineIsHidden(widget.doc, line) && widget.height != null) {
5927 var oldHeight = widget.height;
5928 widget.height = null;
5929 var dHeight = widgetHeight(widget) - oldHeight;
5930 if (dHeight)
5931 { updateLineHeight(line, line.height + dHeight); }
5932 }
5933 signalLater(cm, "markerChanged", cm, this$1);
5934 });
5935 };
5936
5937 TextMarker.prototype.attachLine = function (line) {
5938 if (!this.lines.length && this.doc.cm) {
5939 var op = this.doc.cm.curOp;
5940 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
5941 { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
5942 }
5943 this.lines.push(line);
5944 };
5945
5946 TextMarker.prototype.detachLine = function (line) {
5947 this.lines.splice(indexOf(this.lines, line), 1);
5948 if (!this.lines.length && this.doc.cm) {
5949 var op = this.doc.cm.curOp
5950 ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
5951 }
5952 };
5953 eventMixin(TextMarker);
5954
5955 // Create a marker, wire it up to the right lines, and
5956 function markText(doc, from, to, options, type) {
5957 // Shared markers (across linked documents) are handled separately
5958 // (markTextShared will call out to this again, once per
5959 // document).
5960 if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
5961 // Ensure we are in an operation.
5962 if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
5963
5964 var marker = new TextMarker(doc, type), diff = cmp(from, to);
5965 if (options) { copyObj(options, marker, false); }
5966 // Don't connect empty markers unless clearWhenEmpty is false
5967 if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
5968 { return marker }
5969 if (marker.replacedWith) {
5970 // Showing up as a widget implies collapsed (widget replaces text)
5971 marker.collapsed = true;
5972 marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
5973 if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
5974 if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
5975 }
5976 if (marker.collapsed) {
5977 if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
5978 from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
5979 { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
5980 seeCollapsedSpans();
5981 }
5982
5983 if (marker.addToHistory)
5984 { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
5985
5986 var curLine = from.line, cm = doc.cm, updateMaxLine;
5987 doc.iter(curLine, to.line + 1, function (line) {
5988 if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
5989 { updateMaxLine = true; }
5990 if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
5991 addMarkedSpan(line, new MarkedSpan(marker,
5992 curLine == from.line ? from.ch : null,
5993 curLine == to.line ? to.ch : null));
5994 ++curLine;
5995 });
5996 // lineIsHidden depends on the presence of the spans, so needs a second pass
5997 if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
5998 if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
5999 }); }
6000
6001 if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
6002
6003 if (marker.readOnly) {
6004 seeReadOnlySpans();
6005 if (doc.history.done.length || doc.history.undone.length)
6006 { doc.clearHistory(); }
6007 }
6008 if (marker.collapsed) {
6009 marker.id = ++nextMarkerId;
6010 marker.atomic = true;
6011 }
6012 if (cm) {
6013 // Sync editor state
6014 if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
6015 if (marker.collapsed)
6016 { regChange(cm, from.line, to.line + 1); }
6017 else if (marker.className || marker.startStyle || marker.endStyle || marker.css ||
6018 marker.attributes || marker.title)
6019 { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
6020 if (marker.atomic) { reCheckSelection(cm.doc); }
6021 signalLater(cm, "markerAdded", cm, marker);
6022 }
6023 return marker
6024 }
6025
6026 // SHARED TEXTMARKERS
6027
6028 // A shared marker spans multiple linked documents. It is
6029 // implemented as a meta-marker-object controlling multiple normal
6030 // markers.
6031 var SharedTextMarker = function(markers, primary) {
6032 var this$1 = this;
6033
6034 this.markers = markers;
6035 this.primary = primary;
6036 for (var i = 0; i < markers.length; ++i)
6037 { markers[i].parent = this$1; }
6038 };
6039
6040 SharedTextMarker.prototype.clear = function () {
6041 var this$1 = this;
6042
6043 if (this.explicitlyCleared) { return }
6044 this.explicitlyCleared = true;
6045 for (var i = 0; i < this.markers.length; ++i)
6046 { this$1.markers[i].clear(); }
6047 signalLater(this, "clear");
6048 };
6049
6050 SharedTextMarker.prototype.find = function (side, lineObj) {
6051 return this.primary.find(side, lineObj)
6052 };
6053 eventMixin(SharedTextMarker);
6054
6055 function markTextShared(doc, from, to, options, type) {
6056 options = copyObj(options);
6057 options.shared = false;
6058 var markers = [markText(doc, from, to, options, type)], primary = markers[0];
6059 var widget = options.widgetNode;
6060 linkedDocs(doc, function (doc) {
6061 if (widget) { options.widgetNode = widget.cloneNode(true); }
6062 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
6063 for (var i = 0; i < doc.linked.length; ++i)
6064 { if (doc.linked[i].isParent) { return } }
6065 primary = lst(markers);
6066 });
6067 return new SharedTextMarker(markers, primary)
6068 }
6069
6070 function findSharedMarkers(doc) {
6071 return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
6072 }
6073
6074 function copySharedMarkers(doc, markers) {
6075 for (var i = 0; i < markers.length; i++) {
6076 var marker = markers[i], pos = marker.find();
6077 var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
6078 if (cmp(mFrom, mTo)) {
6079 var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
6080 marker.markers.push(subMark);
6081 subMark.parent = marker;
6082 }
6083 }
6084 }
6085
6086 function detachSharedMarkers(markers) {
6087 var loop = function ( i ) {
6088 var marker = markers[i], linked = [marker.primary.doc];
6089 linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
6090 for (var j = 0; j < marker.markers.length; j++) {
6091 var subMarker = marker.markers[j];
6092 if (indexOf(linked, subMarker.doc) == -1) {
6093 subMarker.parent = null;
6094 marker.markers.splice(j--, 1);
6095 }
6096 }
6097 };
6098
6099 for (var i = 0; i < markers.length; i++) loop( i );
6100 }
6101
6102 var nextDocId = 0;
6103 var Doc = function(text, mode, firstLine, lineSep, direction) {
6104 if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
6105 if (firstLine == null) { firstLine = 0; }
6106
6107 BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
6108 this.first = firstLine;
6109 this.scrollTop = this.scrollLeft = 0;
6110 this.cantEdit = false;
6111 this.cleanGeneration = 1;
6112 this.modeFrontier = this.highlightFrontier = firstLine;
6113 var start = Pos(firstLine, 0);
6114 this.sel = simpleSelection(start);
6115 this.history = new History(null);
6116 this.id = ++nextDocId;
6117 this.modeOption = mode;
6118 this.lineSep = lineSep;
6119 this.direction = (direction == "rtl") ? "rtl" : "ltr";
6120 this.extend = false;
6121
6122 if (typeof text == "string") { text = this.splitLines(text); }
6123 updateDoc(this, {from: start, to: start, text: text});
6124 setSelection(this, simpleSelection(start), sel_dontScroll);
6125 };
6126
6127 Doc.prototype = createObj(BranchChunk.prototype, {
6128 constructor: Doc,
6129 // Iterate over the document. Supports two forms -- with only one
6130 // argument, it calls that for each line in the document. With
6131 // three, it iterates over the range given by the first two (with
6132 // the second being non-inclusive).
6133 iter: function(from, to, op) {
6134 if (op) { this.iterN(from - this.first, to - from, op); }
6135 else { this.iterN(this.first, this.first + this.size, from); }
6136 },
6137
6138 // Non-public interface for adding and removing lines.
6139 insert: function(at, lines) {
6140 var height = 0;
6141 for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
6142 this.insertInner(at - this.first, lines, height);
6143 },
6144 remove: function(at, n) { this.removeInner(at - this.first, n); },
6145
6146 // From here, the methods are part of the public interface. Most
6147 // are also available from CodeMirror (editor) instances.
6148
6149 getValue: function(lineSep) {
6150 var lines = getLines(this, this.first, this.first + this.size);
6151 if (lineSep === false) { return lines }
6152 return lines.join(lineSep || this.lineSeparator())
6153 },
6154 setValue: docMethodOp(function(code) {
6155 var top = Pos(this.first, 0), last = this.first + this.size - 1;
6156 makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
6157 text: this.splitLines(code), origin: "setValue", full: true}, true);
6158 if (this.cm) { scrollToCoords(this.cm, 0, 0); }
6159 setSelection(this, simpleSelection(top), sel_dontScroll);
6160 }),
6161 replaceRange: function(code, from, to, origin) {
6162 from = clipPos(this, from);
6163 to = to ? clipPos(this, to) : from;
6164 replaceRange(this, code, from, to, origin);
6165 },
6166 getRange: function(from, to, lineSep) {
6167 var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
6168 if (lineSep === false) { return lines }
6169 return lines.join(lineSep || this.lineSeparator())
6170 },
6171
6172 getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
6173
6174 getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
6175 getLineNumber: function(line) {return lineNo(line)},
6176
6177 getLineHandleVisualStart: function(line) {
6178 if (typeof line == "number") { line = getLine(this, line); }
6179 return visualLine(line)
6180 },
6181
6182 lineCount: function() {return this.size},
6183 firstLine: function() {return this.first},
6184 lastLine: function() {return this.first + this.size - 1},
6185
6186 clipPos: function(pos) {return clipPos(this, pos)},
6187
6188 getCursor: function(start) {
6189 var range$$1 = this.sel.primary(), pos;
6190 if (start == null || start == "head") { pos = range$$1.head; }
6191 else if (start == "anchor") { pos = range$$1.anchor; }
6192 else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
6193 else { pos = range$$1.from(); }
6194 return pos
6195 },
6196 listSelections: function() { return this.sel.ranges },
6197 somethingSelected: function() {return this.sel.somethingSelected()},
6198
6199 setCursor: docMethodOp(function(line, ch, options) {
6200 setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
6201 }),
6202 setSelection: docMethodOp(function(anchor, head, options) {
6203 setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
6204 }),
6205 extendSelection: docMethodOp(function(head, other, options) {
6206 extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
6207 }),
6208 extendSelections: docMethodOp(function(heads, options) {
6209 extendSelections(this, clipPosArray(this, heads), options);
6210 }),
6211 extendSelectionsBy: docMethodOp(function(f, options) {
6212 var heads = map(this.sel.ranges, f);
6213 extendSelections(this, clipPosArray(this, heads), options);
6214 }),
6215 setSelections: docMethodOp(function(ranges, primary, options) {
6216 var this$1 = this;
6217
6218 if (!ranges.length) { return }
8315 var out = [];
6219 var out = [];
8316 for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
6220 for (var i = 0; i < ranges.length; i++)
8317 return out;
6221 { out[i] = new Range(clipPos(this$1, ranges[i].anchor),
8318 }
6222 clipPos(this$1, ranges[i].head)); }
8319
6223 if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
8320 function nothing() {}
6224 setSelection(this, normalizeSelection(this.cm, out, primary), options);
8321
6225 }),
8322 function createObj(base, props) {
6226 addSelection: docMethodOp(function(anchor, head, options) {
8323 var inst;
6227 var ranges = this.sel.ranges.slice(0);
8324 if (Object.create) {
6228 ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
8325 inst = Object.create(base);
6229 setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options);
6230 }),
6231
6232 getSelection: function(lineSep) {
6233 var this$1 = this;
6234
6235 var ranges = this.sel.ranges, lines;
6236 for (var i = 0; i < ranges.length; i++) {
6237 var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
6238 lines = lines ? lines.concat(sel) : sel;
6239 }
6240 if (lineSep === false) { return lines }
6241 else { return lines.join(lineSep || this.lineSeparator()) }
6242 },
6243 getSelections: function(lineSep) {
6244 var this$1 = this;
6245
6246 var parts = [], ranges = this.sel.ranges;
6247 for (var i = 0; i < ranges.length; i++) {
6248 var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
6249 if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }
6250 parts[i] = sel;
6251 }
6252 return parts
6253 },
6254 replaceSelection: function(code, collapse, origin) {
6255 var dup = [];
6256 for (var i = 0; i < this.sel.ranges.length; i++)
6257 { dup[i] = code; }
6258 this.replaceSelections(dup, collapse, origin || "+input");
6259 },
6260 replaceSelections: docMethodOp(function(code, collapse, origin) {
6261 var this$1 = this;
6262
6263 var changes = [], sel = this.sel;
6264 for (var i = 0; i < sel.ranges.length; i++) {
6265 var range$$1 = sel.ranges[i];
6266 changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};
6267 }
6268 var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
6269 for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
6270 { makeChange(this$1, changes[i$1]); }
6271 if (newSel) { setSelectionReplaceHistory(this, newSel); }
6272 else if (this.cm) { ensureCursorVisible(this.cm); }
6273 }),
6274 undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
6275 redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
6276 undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
6277 redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
6278
6279 setExtending: function(val) {this.extend = val;},
6280 getExtending: function() {return this.extend},
6281
6282 historySize: function() {
6283 var hist = this.history, done = 0, undone = 0;
6284 for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
6285 for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
6286 return {undo: done, redo: undone}
6287 },
6288 clearHistory: function() {this.history = new History(this.history.maxGeneration);},
6289
6290 markClean: function() {
6291 this.cleanGeneration = this.changeGeneration(true);
6292 },
6293 changeGeneration: function(forceSplit) {
6294 if (forceSplit)
6295 { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
6296 return this.history.generation
6297 },
6298 isClean: function (gen) {
6299 return this.history.generation == (gen || this.cleanGeneration)
6300 },
6301
6302 getHistory: function() {
6303 return {done: copyHistoryArray(this.history.done),
6304 undone: copyHistoryArray(this.history.undone)}
6305 },
6306 setHistory: function(histData) {
6307 var hist = this.history = new History(this.history.maxGeneration);
6308 hist.done = copyHistoryArray(histData.done.slice(0), null, true);
6309 hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
6310 },
6311
6312 setGutterMarker: docMethodOp(function(line, gutterID, value) {
6313 return changeLine(this, line, "gutter", function (line) {
6314 var markers = line.gutterMarkers || (line.gutterMarkers = {});
6315 markers[gutterID] = value;
6316 if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
6317 return true
6318 })
6319 }),
6320
6321 clearGutter: docMethodOp(function(gutterID) {
6322 var this$1 = this;
6323
6324 this.iter(function (line) {
6325 if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
6326 changeLine(this$1, line, "gutter", function () {
6327 line.gutterMarkers[gutterID] = null;
6328 if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
6329 return true
6330 });
6331 }
6332 });
6333 }),
6334
6335 lineInfo: function(line) {
6336 var n;
6337 if (typeof line == "number") {
6338 if (!isLine(this, line)) { return null }
6339 n = line;
6340 line = getLine(this, line);
6341 if (!line) { return null }
8326 } else {
6342 } else {
8327 nothing.prototype = base;
6343 n = lineNo(line);
8328 inst = new nothing();
6344 if (n == null) { return null }
8329 }
6345 }
8330 if (props) copyObj(props, inst);
6346 return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
8331 return inst;
6347 textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
8332 };
6348 widgets: line.widgets}
8333
6349 },
8334 function copyObj(obj, target, overwrite) {
6350
8335 if (!target) target = {};
6351 addLineClass: docMethodOp(function(handle, where, cls) {
8336 for (var prop in obj)
6352 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
8337 if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
6353 var prop = where == "text" ? "textClass"
8338 target[prop] = obj[prop];
6354 : where == "background" ? "bgClass"
8339 return target;
6355 : where == "gutter" ? "gutterClass" : "wrapClass";
8340 }
6356 if (!line[prop]) { line[prop] = cls; }
8341
6357 else if (classTest(cls).test(line[prop])) { return false }
8342 function bind(f) {
6358 else { line[prop] += " " + cls; }
8343 var args = Array.prototype.slice.call(arguments, 1);
6359 return true
8344 return function(){return f.apply(null, args);};
6360 })
8345 }
6361 }),
8346
6362 removeLineClass: docMethodOp(function(handle, where, cls) {
8347 var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
6363 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
8348 var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
6364 var prop = where == "text" ? "textClass"
8349 return /\w/.test(ch) || ch > "\x80" &&
6365 : where == "background" ? "bgClass"
8350 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
6366 : where == "gutter" ? "gutterClass" : "wrapClass";
8351 };
6367 var cur = line[prop];
8352 function isWordChar(ch, helper) {
6368 if (!cur) { return false }
8353 if (!helper) return isWordCharBasic(ch);
6369 else if (cls == null) { line[prop] = null; }
8354 if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
6370 else {
8355 return helper.test(ch);
6371 var found = cur.match(classTest(cls));
8356 }
6372 if (!found) { return false }
8357
6373 var end = found.index + found[0].length;
8358 function isEmpty(obj) {
6374 line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
8359 for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
6375 }
8360 return true;
6376 return true
8361 }
6377 })
8362
6378 }),
8363 // Extending unicode characters. A series of a non-extending char +
6379
8364 // any number of extending chars is treated as a single unit as far
6380 addLineWidget: docMethodOp(function(handle, node, options) {
8365 // as editing and measuring is concerned. This is not fully correct,
6381 return addLineWidget(this, handle, node, options)
8366 // since some scripts/fonts/browsers also treat other configurations
6382 }),
8367 // of code points as a group.
6383 removeLineWidget: function(widget) { widget.clear(); },
8368 var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
6384
8369 function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
6385 markText: function(from, to, options) {
8370
6386 return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
8371 // DOM UTILITIES
6387 },
8372
6388 setBookmark: function(pos, options) {
8373 function elt(tag, content, className, style) {
6389 var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
8374 var e = document.createElement(tag);
6390 insertLeft: options && options.insertLeft,
8375 if (className) e.className = className;
6391 clearWhenEmpty: false, shared: options && options.shared,
8376 if (style) e.style.cssText = style;
6392 handleMouseEvents: options && options.handleMouseEvents};
8377 if (typeof content == "string") e.appendChild(document.createTextNode(content));
6393 pos = clipPos(this, pos);
8378 else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
6394 return markText(this, pos, pos, realOpts, "bookmark")
8379 return e;
6395 },
8380 }
6396 findMarksAt: function(pos) {
8381
6397 pos = clipPos(this, pos);
8382 var range;
6398 var markers = [], spans = getLine(this, pos.line).markedSpans;
8383 if (document.createRange) range = function(node, start, end, endNode) {
6399 if (spans) { for (var i = 0; i < spans.length; ++i) {
8384 var r = document.createRange();
6400 var span = spans[i];
8385 r.setEnd(endNode || node, end);
6401 if ((span.from == null || span.from <= pos.ch) &&
8386 r.setStart(node, start);
6402 (span.to == null || span.to >= pos.ch))
8387 return r;
6403 { markers.push(span.marker.parent || span.marker); }
8388 };
6404 } }
8389 else range = function(node, start, end) {
6405 return markers
8390 var r = document.body.createTextRange();
6406 },
8391 try { r.moveToElementText(node.parentNode); }
6407 findMarks: function(from, to, filter) {
8392 catch(e) { return r; }
6408 from = clipPos(this, from); to = clipPos(this, to);
8393 r.collapse(true);
6409 var found = [], lineNo$$1 = from.line;
8394 r.moveEnd("character", end);
6410 this.iter(from.line, to.line + 1, function (line) {
8395 r.moveStart("character", start);
6411 var spans = line.markedSpans;
8396 return r;
6412 if (spans) { for (var i = 0; i < spans.length; i++) {
8397 };
6413 var span = spans[i];
8398
6414 if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
8399 function removeChildren(e) {
6415 span.from == null && lineNo$$1 != from.line ||
8400 for (var count = e.childNodes.length; count > 0; --count)
6416 span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
8401 e.removeChild(e.firstChild);
6417 (!filter || filter(span.marker)))
8402 return e;
6418 { found.push(span.marker.parent || span.marker); }
8403 }
6419 } }
8404
6420 ++lineNo$$1;
8405 function removeChildrenAndAdd(parent, e) {
6421 });
8406 return removeChildren(parent).appendChild(e);
6422 return found
8407 }
6423 },
8408
6424 getAllMarks: function() {
8409 var contains = CodeMirror.contains = function(parent, child) {
6425 var markers = [];
8410 if (child.nodeType == 3) // Android browser always returns false when child is a textnode
6426 this.iter(function (line) {
8411 child = child.parentNode;
6427 var sps = line.markedSpans;
8412 if (parent.contains)
6428 if (sps) { for (var i = 0; i < sps.length; ++i)
8413 return parent.contains(child);
6429 { if (sps[i].from != null) { markers.push(sps[i].marker); } } }
8414 do {
6430 });
8415 if (child.nodeType == 11) child = child.host;
6431 return markers
8416 if (child == parent) return true;
6432 },
8417 } while (child = child.parentNode);
6433
8418 };
6434 posFromIndex: function(off) {
8419
6435 var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
8420 function activeElt() {
6436 this.iter(function (line) {
8421 var activeElement = document.activeElement;
6437 var sz = line.text.length + sepSize;
8422 while (activeElement && activeElement.root && activeElement.root.activeElement)
6438 if (sz > off) { ch = off; return true }
8423 activeElement = activeElement.root.activeElement;
6439 off -= sz;
8424 return activeElement;
6440 ++lineNo$$1;
8425 }
6441 });
8426 // Older versions of IE throws unspecified error when touching
6442 return clipPos(this, Pos(lineNo$$1, ch))
8427 // document.activeElement in some cases (during loading, in iframe)
6443 },
8428 if (ie && ie_version < 11) activeElt = function() {
6444 indexFromPos: function (coords) {
8429 try { return document.activeElement; }
6445 coords = clipPos(this, coords);
8430 catch(e) { return document.body; }
6446 var index = coords.ch;
8431 };
6447 if (coords.line < this.first || coords.ch < 0) { return 0 }
8432
6448 var sepSize = this.lineSeparator().length;
8433 function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }
6449 this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
8434 var rmClass = CodeMirror.rmClass = function(node, cls) {
6450 index += line.text.length + sepSize;
8435 var current = node.className;
6451 });
8436 var match = classTest(cls).exec(current);
6452 return index
8437 if (match) {
6453 },
8438 var after = current.slice(match.index + match[0].length);
6454
8439 node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
6455 copy: function(copyHistory) {
8440 }
6456 var doc = new Doc(getLines(this, this.first, this.first + this.size),
8441 };
6457 this.modeOption, this.first, this.lineSep, this.direction);
8442 var addClass = CodeMirror.addClass = function(node, cls) {
6458 doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
8443 var current = node.className;
6459 doc.sel = this.sel;
8444 if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls;
6460 doc.extend = false;
8445 };
6461 if (copyHistory) {
8446 function joinClasses(a, b) {
6462 doc.history.undoDepth = this.history.undoDepth;
8447 var as = a.split(" ");
6463 doc.setHistory(this.getHistory());
8448 for (var i = 0; i < as.length; i++)
6464 }
8449 if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
6465 return doc
8450 return b;
6466 },
8451 }
6467
8452
6468 linkedDoc: function(options) {
8453 // WINDOW-WIDE EVENTS
6469 if (!options) { options = {}; }
6470 var from = this.first, to = this.first + this.size;
6471 if (options.from != null && options.from > from) { from = options.from; }
6472 if (options.to != null && options.to < to) { to = options.to; }
6473 var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
6474 if (options.sharedHist) { copy.history = this.history
6475 ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
6476 copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
6477 copySharedMarkers(copy, findSharedMarkers(this));
6478 return copy
6479 },
6480 unlinkDoc: function(other) {
6481 var this$1 = this;
6482
6483 if (other instanceof CodeMirror) { other = other.doc; }
6484 if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
6485 var link = this$1.linked[i];
6486 if (link.doc != other) { continue }
6487 this$1.linked.splice(i, 1);
6488 other.unlinkDoc(this$1);
6489 detachSharedMarkers(findSharedMarkers(this$1));
6490 break
6491 } }
6492 // If the histories were shared, split them again
6493 if (other.history == this.history) {
6494 var splitIds = [other.id];
6495 linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
6496 other.history = new History(null);
6497 other.history.done = copyHistoryArray(this.history.done, splitIds);
6498 other.history.undone = copyHistoryArray(this.history.undone, splitIds);
6499 }
6500 },
6501 iterLinkedDocs: function(f) {linkedDocs(this, f);},
6502
6503 getMode: function() {return this.mode},
6504 getEditor: function() {return this.cm},
6505
6506 splitLines: function(str) {
6507 if (this.lineSep) { return str.split(this.lineSep) }
6508 return splitLinesAuto(str)
6509 },
6510 lineSeparator: function() { return this.lineSep || "\n" },
6511
6512 setDirection: docMethodOp(function (dir) {
6513 if (dir != "rtl") { dir = "ltr"; }
6514 if (dir == this.direction) { return }
6515 this.direction = dir;
6516 this.iter(function (line) { return line.order = null; });
6517 if (this.cm) { directionChanged(this.cm); }
6518 })
6519 });
6520
6521 // Public alias.
6522 Doc.prototype.eachLine = Doc.prototype.iter;
6523
6524 // Kludge to work around strange IE behavior where it'll sometimes
6525 // re-fire a series of drag-related events right after the drop (#1551)
6526 var lastDrop = 0;
6527
6528 function onDrop(e) {
6529 var cm = this;
6530 clearDragCursor(cm);
6531 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
6532 { return }
6533 e_preventDefault(e);
6534 if (ie) { lastDrop = +new Date; }
6535 var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
6536 if (!pos || cm.isReadOnly()) { return }
6537 // Might be a file drop, in which case we simply extract the text
6538 // and insert it.
6539 if (files && files.length && window.FileReader && window.File) {
6540 var n = files.length, text = Array(n), read = 0;
6541 var loadFile = function (file, i) {
6542 if (cm.options.allowDropFileTypes &&
6543 indexOf(cm.options.allowDropFileTypes, file.type) == -1)
6544 { return }
6545
6546 var reader = new FileReader;
6547 reader.onload = operation(cm, function () {
6548 var content = reader.result;
6549 if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
6550 text[i] = content;
6551 if (++read == n) {
6552 pos = clipPos(cm.doc, pos);
6553 var change = {from: pos, to: pos,
6554 text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
6555 origin: "paste"};
6556 makeChange(cm.doc, change);
6557 setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
6558 }
6559 });
6560 reader.readAsText(file);
6561 };
6562 for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
6563 } else { // Normal drop
6564 // Don't do a replace if the drop happened inside of the selected text.
6565 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
6566 cm.state.draggingText(e);
6567 // Ensure the editor is re-focused
6568 setTimeout(function () { return cm.display.input.focus(); }, 20);
6569 return
6570 }
6571 try {
6572 var text$1 = e.dataTransfer.getData("Text");
6573 if (text$1) {
6574 var selected;
6575 if (cm.state.draggingText && !cm.state.draggingText.copy)
6576 { selected = cm.listSelections(); }
6577 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
6578 if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
6579 { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
6580 cm.replaceSelection(text$1, "around", "paste");
6581 cm.display.input.focus();
6582 }
6583 }
6584 catch(e){}
6585 }
6586 }
6587
6588 function onDragStart(cm, e) {
6589 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
6590 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
6591
6592 e.dataTransfer.setData("Text", cm.getSelection());
6593 e.dataTransfer.effectAllowed = "copyMove";
6594
6595 // Use dummy image instead of default browsers image.
6596 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
6597 if (e.dataTransfer.setDragImage && !safari) {
6598 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
6599 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
6600 if (presto) {
6601 img.width = img.height = 1;
6602 cm.display.wrapper.appendChild(img);
6603 // Force a relayout, or Opera won't use our image for some obscure reason
6604 img._top = img.offsetTop;
6605 }
6606 e.dataTransfer.setDragImage(img, 0, 0);
6607 if (presto) { img.parentNode.removeChild(img); }
6608 }
6609 }
6610
6611 function onDragOver(cm, e) {
6612 var pos = posFromMouse(cm, e);
6613 if (!pos) { return }
6614 var frag = document.createDocumentFragment();
6615 drawSelectionCursor(cm, pos, frag);
6616 if (!cm.display.dragCursor) {
6617 cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
6618 cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
6619 }
6620 removeChildrenAndAdd(cm.display.dragCursor, frag);
6621 }
6622
6623 function clearDragCursor(cm) {
6624 if (cm.display.dragCursor) {
6625 cm.display.lineSpace.removeChild(cm.display.dragCursor);
6626 cm.display.dragCursor = null;
6627 }
6628 }
8454
6629
8455 // These must be handled carefully, because naively registering a
6630 // These must be handled carefully, because naively registering a
8456 // handler for each editor will cause the editors to never be
6631 // handler for each editor will cause the editors to never be
8457 // garbage collected.
6632 // garbage collected.
8458
6633
8459 function forEachCodeMirror(f) {
6634 function forEachCodeMirror(f) {
8460 if (!document.body.getElementsByClassName) return;
6635 if (!document.getElementsByClassName) { return }
8461 var byClass = document.body.getElementsByClassName("CodeMirror");
6636 var byClass = document.getElementsByClassName("CodeMirror"), editors = [];
8462 for (var i = 0; i < byClass.length; i++) {
6637 for (var i = 0; i < byClass.length; i++) {
8463 var cm = byClass[i].CodeMirror;
6638 var cm = byClass[i].CodeMirror;
8464 if (cm) f(cm);
6639 if (cm) { editors.push(cm); }
8465 }
6640 }
6641 if (editors.length) { editors[0].operation(function () {
6642 for (var i = 0; i < editors.length; i++) { f(editors[i]); }
6643 }); }
8466 }
6644 }
8467
6645
8468 var globalsRegistered = false;
6646 var globalsRegistered = false;
8469 function ensureGlobalHandlers() {
6647 function ensureGlobalHandlers() {
8470 if (globalsRegistered) return;
6648 if (globalsRegistered) { return }
8471 registerGlobalHandlers();
6649 registerGlobalHandlers();
8472 globalsRegistered = true;
6650 globalsRegistered = true;
8473 }
6651 }
@@ -8475,416 +6653,3131 b''
8475 // When the window resizes, we need to refresh active editors.
6653 // When the window resizes, we need to refresh active editors.
8476 var resizeTimer;
6654 var resizeTimer;
8477 on(window, "resize", function() {
6655 on(window, "resize", function() {
8478 if (resizeTimer == null) resizeTimer = setTimeout(function() {
6656 if (resizeTimer == null) { resizeTimer = setTimeout(function () {
8479 resizeTimer = null;
6657 resizeTimer = null;
8480 forEachCodeMirror(onResize);
6658 forEachCodeMirror(onResize);
8481 }, 100);
6659 }, 100); }
8482 });
6660 });
8483 // When the window loses focus, we want to show the editor as blurred
6661 // When the window loses focus, we want to show the editor as blurred
8484 on(window, "blur", function() {
6662 on(window, "blur", function () { return forEachCodeMirror(onBlur); });
8485 forEachCodeMirror(onBlur);
6663 }
8486 });
6664 // Called when the window resizes
8487 }
6665 function onResize(cm) {
8488
6666 var d = cm.display;
8489 // FEATURE DETECTION
6667 // Might be a text scaling operation, clear size caches.
8490
6668 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
8491 // Detect drag-and-drop
6669 d.scrollbarsClipped = false;
8492 var dragAndDrop = function() {
6670 cm.setSize();
8493 // There is *some* kind of drag-and-drop support in IE6-8, but I
6671 }
8494 // couldn't get it to work yet.
6672
8495 if (ie && ie_version < 9) return false;
6673 var keyNames = {
8496 var div = elt('div');
6674 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
8497 return "draggable" in div || "dragDrop" in div;
8498 }();
8499
8500 var zwspSupported;
8501 function zeroWidthElement(measure) {
8502 if (zwspSupported == null) {
8503 var test = elt("span", "\u200b");
8504 removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
8505 if (measure.firstChild.offsetHeight != 0)
8506 zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
8507 }
8508 var node = zwspSupported ? elt("span", "\u200b") :
8509 elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
8510 node.setAttribute("cm-text", "");
8511 return node;
8512 }
8513
8514 // Feature-detect IE's crummy client rect reporting for bidi text
8515 var badBidiRects;
8516 function hasBadBidiRects(measure) {
8517 if (badBidiRects != null) return badBidiRects;
8518 var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
8519 var r0 = range(txt, 0, 1).getBoundingClientRect();
8520 if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
8521 var r1 = range(txt, 1, 2).getBoundingClientRect();
8522 return badBidiRects = (r1.right - r0.right < 3);
8523 }
8524
8525 // See if "".split is the broken IE version, if so, provide an
8526 // alternative way to split lines.
8527 var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
8528 var pos = 0, result = [], l = string.length;
8529 while (pos <= l) {
8530 var nl = string.indexOf("\n", pos);
8531 if (nl == -1) nl = string.length;
8532 var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
8533 var rt = line.indexOf("\r");
8534 if (rt != -1) {
8535 result.push(line.slice(0, rt));
8536 pos += rt + 1;
8537 } else {
8538 result.push(line);
8539 pos = nl + 1;
8540 }
8541 }
8542 return result;
8543 } : function(string){return string.split(/\r\n?|\n/);};
8544
8545 var hasSelection = window.getSelection ? function(te) {
8546 try { return te.selectionStart != te.selectionEnd; }
8547 catch(e) { return false; }
8548 } : function(te) {
8549 try {var range = te.ownerDocument.selection.createRange();}
8550 catch(e) {}
8551 if (!range || range.parentElement() != te) return false;
8552 return range.compareEndPoints("StartToEnd", range) != 0;
8553 };
8554
8555 var hasCopyEvent = (function() {
8556 var e = elt("div");
8557 if ("oncopy" in e) return true;
8558 e.setAttribute("oncopy", "return;");
8559 return typeof e.oncopy == "function";
8560 })();
8561
8562 var badZoomedRects = null;
8563 function hasBadZoomedRects(measure) {
8564 if (badZoomedRects != null) return badZoomedRects;
8565 var node = removeChildrenAndAdd(measure, elt("span", "x"));
8566 var normal = node.getBoundingClientRect();
8567 var fromRange = range(node, 0, 1).getBoundingClientRect();
8568 return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
8569 }
8570
8571 // KEY NAMES
8572
8573 var keyNames = CodeMirror.keyNames = {
8574 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
8575 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
6675 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
8576 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
6676 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
8577 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
6677 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
8578 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
6678 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock",
8579 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
6679 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
8580 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
6680 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
8581 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
6681 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
8582 };
6682 };
8583 (function() {
6683
8584 // Number keys
6684 // Number keys
8585 for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
6685 for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
8586 // Alphabetic keys
6686 // Alphabetic keys
8587 for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
6687 for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
8588 // Function keys
6688 // Function keys
8589 for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
6689 for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
8590 })();
6690
8591
6691 var keyMap = {};
8592 // BIDI HELPERS
6692
8593
6693 keyMap.basic = {
8594 function iterateBidiSections(order, from, to, f) {
6694 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
8595 if (!order) return f(from, to, "ltr");
6695 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
8596 var found = false;
6696 "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
8597 for (var i = 0; i < order.length; ++i) {
6697 "Tab": "defaultTab", "Shift-Tab": "indentAuto",
8598 var part = order[i];
6698 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
8599 if (part.from < to && part.to > from || from == to && part.to == from) {
6699 "Esc": "singleSelection"
8600 f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
6700 };
8601 found = true;
6701 // Note that the save and find-related commands aren't defined by
8602 }
6702 // default. User code or addons can define them. Unknown commands
8603 }
6703 // are simply ignored.
8604 if (!found) f(from, to, "ltr");
6704 keyMap.pcDefault = {
8605 }
6705 "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
8606
6706 "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
8607 function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
6707 "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
8608 function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
6708 "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
8609
6709 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
8610 function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
6710 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
8611 function lineRight(line) {
6711 "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
8612 var order = getOrder(line);
6712 "fallthrough": "basic"
8613 if (!order) return line.text.length;
6713 };
8614 return bidiRight(lst(order));
6714 // Very basic readline/emacs-style bindings, which are standard on Mac.
8615 }
6715 keyMap.emacsy = {
6716 "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
6717 "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
6718 "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
6719 "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
6720 "Ctrl-O": "openLine"
6721 };
6722 keyMap.macDefault = {
6723 "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
6724 "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
6725 "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
6726 "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
6727 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
6728 "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
6729 "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
6730 "fallthrough": ["basic", "emacsy"]
6731 };
6732 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
6733
6734 // KEYMAP DISPATCH
6735
6736 function normalizeKeyName(name) {
6737 var parts = name.split(/-(?!$)/);
6738 name = parts[parts.length - 1];
6739 var alt, ctrl, shift, cmd;
6740 for (var i = 0; i < parts.length - 1; i++) {
6741 var mod = parts[i];
6742 if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
6743 else if (/^a(lt)?$/i.test(mod)) { alt = true; }
6744 else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
6745 else if (/^s(hift)?$/i.test(mod)) { shift = true; }
6746 else { throw new Error("Unrecognized modifier name: " + mod) }
6747 }
6748 if (alt) { name = "Alt-" + name; }
6749 if (ctrl) { name = "Ctrl-" + name; }
6750 if (cmd) { name = "Cmd-" + name; }
6751 if (shift) { name = "Shift-" + name; }
6752 return name
6753 }
6754
6755 // This is a kludge to keep keymaps mostly working as raw objects
6756 // (backwards compatibility) while at the same time support features
6757 // like normalization and multi-stroke key bindings. It compiles a
6758 // new normalized keymap, and then updates the old object to reflect
6759 // this.
6760 function normalizeKeyMap(keymap) {
6761 var copy = {};
6762 for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
6763 var value = keymap[keyname];
6764 if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
6765 if (value == "...") { delete keymap[keyname]; continue }
6766
6767 var keys = map(keyname.split(" "), normalizeKeyName);
6768 for (var i = 0; i < keys.length; i++) {
6769 var val = (void 0), name = (void 0);
6770 if (i == keys.length - 1) {
6771 name = keys.join(" ");
6772 val = value;
6773 } else {
6774 name = keys.slice(0, i + 1).join(" ");
6775 val = "...";
6776 }
6777 var prev = copy[name];
6778 if (!prev) { copy[name] = val; }
6779 else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
6780 }
6781 delete keymap[keyname];
6782 } }
6783 for (var prop in copy) { keymap[prop] = copy[prop]; }
6784 return keymap
6785 }
6786
6787 function lookupKey(key, map$$1, handle, context) {
6788 map$$1 = getKeyMap(map$$1);
6789 var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
6790 if (found === false) { return "nothing" }
6791 if (found === "...") { return "multi" }
6792 if (found != null && handle(found)) { return "handled" }
6793
6794 if (map$$1.fallthrough) {
6795 if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
6796 { return lookupKey(key, map$$1.fallthrough, handle, context) }
6797 for (var i = 0; i < map$$1.fallthrough.length; i++) {
6798 var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
6799 if (result) { return result }
6800 }
6801 }
6802 }
6803
6804 // Modifier key presses don't count as 'real' key presses for the
6805 // purpose of keymap fallthrough.
6806 function isModifierKey(value) {
6807 var name = typeof value == "string" ? value : keyNames[value.keyCode];
6808 return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
6809 }
6810
6811 function addModifierNames(name, event, noShift) {
6812 var base = name;
6813 if (event.altKey && base != "Alt") { name = "Alt-" + name; }
6814 if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
6815 if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
6816 if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
6817 return name
6818 }
6819
6820 // Look up the name of a key as indicated by an event object.
6821 function keyName(event, noShift) {
6822 if (presto && event.keyCode == 34 && event["char"]) { return false }
6823 var name = keyNames[event.keyCode];
6824 if (name == null || event.altGraphKey) { return false }
6825 // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
6826 // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
6827 if (event.keyCode == 3 && event.code) { name = event.code; }
6828 return addModifierNames(name, event, noShift)
6829 }
6830
6831 function getKeyMap(val) {
6832 return typeof val == "string" ? keyMap[val] : val
6833 }
6834
6835 // Helper for deleting text near the selection(s), used to implement
6836 // backspace, delete, and similar functionality.
6837 function deleteNearSelection(cm, compute) {
6838 var ranges = cm.doc.sel.ranges, kill = [];
6839 // Build up a set of ranges to kill first, merging overlapping
6840 // ranges.
6841 for (var i = 0; i < ranges.length; i++) {
6842 var toKill = compute(ranges[i]);
6843 while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
6844 var replaced = kill.pop();
6845 if (cmp(replaced.from, toKill.from) < 0) {
6846 toKill.from = replaced.from;
6847 break
6848 }
6849 }
6850 kill.push(toKill);
6851 }
6852 // Next, remove those actual ranges.
6853 runInOp(cm, function () {
6854 for (var i = kill.length - 1; i >= 0; i--)
6855 { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
6856 ensureCursorVisible(cm);
6857 });
6858 }
6859
6860 function moveCharLogically(line, ch, dir) {
6861 var target = skipExtendingChars(line.text, ch + dir, dir);
6862 return target < 0 || target > line.text.length ? null : target
6863 }
6864
6865 function moveLogically(line, start, dir) {
6866 var ch = moveCharLogically(line, start.ch, dir);
6867 return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
6868 }
6869
6870 function endOfLine(visually, cm, lineObj, lineNo, dir) {
6871 if (visually) {
6872 var order = getOrder(lineObj, cm.doc.direction);
6873 if (order) {
6874 var part = dir < 0 ? lst(order) : order[0];
6875 var moveInStorageOrder = (dir < 0) == (part.level == 1);
6876 var sticky = moveInStorageOrder ? "after" : "before";
6877 var ch;
6878 // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
6879 // it could be that the last bidi part is not on the last visual line,
6880 // since visual lines contain content order-consecutive chunks.
6881 // Thus, in rtl, we are looking for the first (content-order) character
6882 // in the rtl chunk that is on the last line (that is, the same line
6883 // as the last (content-order) character).
6884 if (part.level > 0 || cm.doc.direction == "rtl") {
6885 var prep = prepareMeasureForLine(cm, lineObj);
6886 ch = dir < 0 ? lineObj.text.length - 1 : 0;
6887 var targetTop = measureCharPrepared(cm, prep, ch).top;
6888 ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
6889 if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
6890 } else { ch = dir < 0 ? part.to : part.from; }
6891 return new Pos(lineNo, ch, sticky)
6892 }
6893 }
6894 return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
6895 }
6896
6897 function moveVisually(cm, line, start, dir) {
6898 var bidi = getOrder(line, cm.doc.direction);
6899 if (!bidi) { return moveLogically(line, start, dir) }
6900 if (start.ch >= line.text.length) {
6901 start.ch = line.text.length;
6902 start.sticky = "before";
6903 } else if (start.ch <= 0) {
6904 start.ch = 0;
6905 start.sticky = "after";
6906 }
6907 var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
6908 if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
6909 // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
6910 // nothing interesting happens.
6911 return moveLogically(line, start, dir)
6912 }
6913
6914 var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
6915 var prep;
6916 var getWrappedLineExtent = function (ch) {
6917 if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
6918 prep = prep || prepareMeasureForLine(cm, line);
6919 return wrappedLineExtentChar(cm, line, prep, ch)
6920 };
6921 var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
6922
6923 if (cm.doc.direction == "rtl" || part.level == 1) {
6924 var moveInStorageOrder = (part.level == 1) == (dir < 0);
6925 var ch = mv(start, moveInStorageOrder ? 1 : -1);
6926 if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
6927 // Case 2: We move within an rtl part or in an rtl editor on the same visual line
6928 var sticky = moveInStorageOrder ? "before" : "after";
6929 return new Pos(start.line, ch, sticky)
6930 }
6931 }
6932
6933 // Case 3: Could not move within this bidi part in this visual line, so leave
6934 // the current bidi part
6935
6936 var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
6937 var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
6938 ? new Pos(start.line, mv(ch, 1), "before")
6939 : new Pos(start.line, ch, "after"); };
6940
6941 for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
6942 var part = bidi[partPos];
6943 var moveInStorageOrder = (dir > 0) == (part.level != 1);
6944 var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
6945 if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
6946 ch = moveInStorageOrder ? part.from : mv(part.to, -1);
6947 if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
6948 }
6949 };
6950
6951 // Case 3a: Look for other bidi parts on the same visual line
6952 var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
6953 if (res) { return res }
6954
6955 // Case 3b: Look for other bidi parts on the next visual line
6956 var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
6957 if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
6958 res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
6959 if (res) { return res }
6960 }
6961
6962 // Case 4: Nowhere to move
6963 return null
6964 }
6965
6966 // Commands are parameter-less actions that can be performed on an
6967 // editor, mostly used for keybindings.
6968 var commands = {
6969 selectAll: selectAll,
6970 singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
6971 killLine: function (cm) { return deleteNearSelection(cm, function (range) {
6972 if (range.empty()) {
6973 var len = getLine(cm.doc, range.head.line).text.length;
6974 if (range.head.ch == len && range.head.line < cm.lastLine())
6975 { return {from: range.head, to: Pos(range.head.line + 1, 0)} }
6976 else
6977 { return {from: range.head, to: Pos(range.head.line, len)} }
6978 } else {
6979 return {from: range.from(), to: range.to()}
6980 }
6981 }); },
6982 deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
6983 from: Pos(range.from().line, 0),
6984 to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
6985 }); }); },
6986 delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
6987 from: Pos(range.from().line, 0), to: range.from()
6988 }); }); },
6989 delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
6990 var top = cm.charCoords(range.head, "div").top + 5;
6991 var leftPos = cm.coordsChar({left: 0, top: top}, "div");
6992 return {from: leftPos, to: range.from()}
6993 }); },
6994 delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
6995 var top = cm.charCoords(range.head, "div").top + 5;
6996 var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
6997 return {from: range.from(), to: rightPos }
6998 }); },
6999 undo: function (cm) { return cm.undo(); },
7000 redo: function (cm) { return cm.redo(); },
7001 undoSelection: function (cm) { return cm.undoSelection(); },
7002 redoSelection: function (cm) { return cm.redoSelection(); },
7003 goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
7004 goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
7005 goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
7006 {origin: "+move", bias: 1}
7007 ); },
7008 goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
7009 {origin: "+move", bias: 1}
7010 ); },
7011 goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
7012 {origin: "+move", bias: -1}
7013 ); },
7014 goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
7015 var top = cm.cursorCoords(range.head, "div").top + 5;
7016 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
7017 }, sel_move); },
7018 goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
7019 var top = cm.cursorCoords(range.head, "div").top + 5;
7020 return cm.coordsChar({left: 0, top: top}, "div")
7021 }, sel_move); },
7022 goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
7023 var top = cm.cursorCoords(range.head, "div").top + 5;
7024 var pos = cm.coordsChar({left: 0, top: top}, "div");
7025 if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
7026 return pos
7027 }, sel_move); },
7028 goLineUp: function (cm) { return cm.moveV(-1, "line"); },
7029 goLineDown: function (cm) { return cm.moveV(1, "line"); },
7030 goPageUp: function (cm) { return cm.moveV(-1, "page"); },
7031 goPageDown: function (cm) { return cm.moveV(1, "page"); },
7032 goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
7033 goCharRight: function (cm) { return cm.moveH(1, "char"); },
7034 goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
7035 goColumnRight: function (cm) { return cm.moveH(1, "column"); },
7036 goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
7037 goGroupRight: function (cm) { return cm.moveH(1, "group"); },
7038 goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
7039 goWordRight: function (cm) { return cm.moveH(1, "word"); },
7040 delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
7041 delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
7042 delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
7043 delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
7044 delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
7045 delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
7046 indentAuto: function (cm) { return cm.indentSelection("smart"); },
7047 indentMore: function (cm) { return cm.indentSelection("add"); },
7048 indentLess: function (cm) { return cm.indentSelection("subtract"); },
7049 insertTab: function (cm) { return cm.replaceSelection("\t"); },
7050 insertSoftTab: function (cm) {
7051 var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
7052 for (var i = 0; i < ranges.length; i++) {
7053 var pos = ranges[i].from();
7054 var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
7055 spaces.push(spaceStr(tabSize - col % tabSize));
7056 }
7057 cm.replaceSelections(spaces);
7058 },
7059 defaultTab: function (cm) {
7060 if (cm.somethingSelected()) { cm.indentSelection("add"); }
7061 else { cm.execCommand("insertTab"); }
7062 },
7063 // Swap the two chars left and right of each selection's head.
7064 // Move cursor behind the two swapped characters afterwards.
7065 //
7066 // Doesn't consider line feeds a character.
7067 // Doesn't scan more than one line above to find a character.
7068 // Doesn't do anything on an empty line.
7069 // Doesn't do anything with non-empty selections.
7070 transposeChars: function (cm) { return runInOp(cm, function () {
7071 var ranges = cm.listSelections(), newSel = [];
7072 for (var i = 0; i < ranges.length; i++) {
7073 if (!ranges[i].empty()) { continue }
7074 var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
7075 if (line) {
7076 if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
7077 if (cur.ch > 0) {
7078 cur = new Pos(cur.line, cur.ch + 1);
7079 cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
7080 Pos(cur.line, cur.ch - 2), cur, "+transpose");
7081 } else if (cur.line > cm.doc.first) {
7082 var prev = getLine(cm.doc, cur.line - 1).text;
7083 if (prev) {
7084 cur = new Pos(cur.line, 1);
7085 cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
7086 prev.charAt(prev.length - 1),
7087 Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
7088 }
7089 }
7090 }
7091 newSel.push(new Range(cur, cur));
7092 }
7093 cm.setSelections(newSel);
7094 }); },
7095 newlineAndIndent: function (cm) { return runInOp(cm, function () {
7096 var sels = cm.listSelections();
7097 for (var i = sels.length - 1; i >= 0; i--)
7098 { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
7099 sels = cm.listSelections();
7100 for (var i$1 = 0; i$1 < sels.length; i$1++)
7101 { cm.indentLine(sels[i$1].from().line, null, true); }
7102 ensureCursorVisible(cm);
7103 }); },
7104 openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
7105 toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
7106 };
7107
8616
7108
8617 function lineStart(cm, lineN) {
7109 function lineStart(cm, lineN) {
8618 var line = getLine(cm.doc, lineN);
7110 var line = getLine(cm.doc, lineN);
8619 var visual = visualLine(line);
7111 var visual = visualLine(line);
8620 if (visual != line) lineN = lineNo(visual);
7112 if (visual != line) { lineN = lineNo(visual); }
8621 var order = getOrder(visual);
7113 return endOfLine(true, cm, visual, lineN, 1)
8622 var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
8623 return Pos(lineN, ch);
8624 }
7114 }
8625 function lineEnd(cm, lineN) {
7115 function lineEnd(cm, lineN) {
8626 var merged, line = getLine(cm.doc, lineN);
7116 var line = getLine(cm.doc, lineN);
8627 while (merged = collapsedSpanAtEnd(line)) {
7117 var visual = visualLineEnd(line);
8628 line = merged.find(1, true).line;
7118 if (visual != line) { lineN = lineNo(visual); }
8629 lineN = null;
7119 return endOfLine(true, cm, line, lineN, -1)
8630 }
8631 var order = getOrder(line);
8632 var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
8633 return Pos(lineN == null ? lineNo(line) : lineN, ch);
8634 }
7120 }
8635 function lineStartSmart(cm, pos) {
7121 function lineStartSmart(cm, pos) {
8636 var start = lineStart(cm, pos.line);
7122 var start = lineStart(cm, pos.line);
8637 var line = getLine(cm.doc, start.line);
7123 var line = getLine(cm.doc, start.line);
8638 var order = getOrder(line);
7124 var order = getOrder(line, cm.doc.direction);
8639 if (!order || order[0].level == 0) {
7125 if (!order || order[0].level == 0) {
8640 var firstNonWS = Math.max(0, line.text.search(/\S/));
7126 var firstNonWS = Math.max(0, line.text.search(/\S/));
8641 var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
7127 var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
8642 return Pos(start.line, inWS ? 0 : firstNonWS);
7128 return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
8643 }
7129 }
8644 return start;
7130 return start
8645 }
7131 }
8646
7132
8647 function compareBidiLevel(order, a, b) {
7133 // Run a handler that was bound to a key.
8648 var linedir = order[0].level;
7134 function doHandleBinding(cm, bound, dropShift) {
8649 if (a == linedir) return true;
7135 if (typeof bound == "string") {
8650 if (b == linedir) return false;
7136 bound = commands[bound];
8651 return a < b;
7137 if (!bound) { return false }
8652 }
7138 }
8653 var bidiOther;
7139 // Ensure previous input has been read, so that the handler sees a
8654 function getBidiPartAt(order, pos) {
7140 // consistent view of the document
8655 bidiOther = null;
7141 cm.display.input.ensurePolled();
8656 for (var i = 0, found; i < order.length; ++i) {
7142 var prevShift = cm.display.shift, done = false;
8657 var cur = order[i];
7143 try {
8658 if (cur.from < pos && cur.to > pos) return i;
7144 if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
8659 if ((cur.from == pos || cur.to == pos)) {
7145 if (dropShift) { cm.display.shift = false; }
8660 if (found == null) {
7146 done = bound(cm) != Pass;
8661 found = i;
7147 } finally {
8662 } else if (compareBidiLevel(order, cur.level, order[found].level)) {
7148 cm.display.shift = prevShift;
8663 if (cur.from != cur.to) bidiOther = found;
7149 cm.state.suppressEdits = false;
8664 return i;
7150 }
7151 return done
7152 }
7153
7154 function lookupKeyForEditor(cm, name, handle) {
7155 for (var i = 0; i < cm.state.keyMaps.length; i++) {
7156 var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
7157 if (result) { return result }
7158 }
7159 return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
7160 || lookupKey(name, cm.options.keyMap, handle, cm)
7161 }
7162
7163 // Note that, despite the name, this function is also used to check
7164 // for bound mouse clicks.
7165
7166 var stopSeq = new Delayed;
7167
7168 function dispatchKey(cm, name, e, handle) {
7169 var seq = cm.state.keySeq;
7170 if (seq) {
7171 if (isModifierKey(name)) { return "handled" }
7172 if (/\'$/.test(name))
7173 { cm.state.keySeq = null; }
7174 else
7175 { stopSeq.set(50, function () {
7176 if (cm.state.keySeq == seq) {
7177 cm.state.keySeq = null;
7178 cm.display.input.reset();
7179 }
7180 }); }
7181 if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true }
7182 }
7183 return dispatchKeyInner(cm, name, e, handle)
7184 }
7185
7186 function dispatchKeyInner(cm, name, e, handle) {
7187 var result = lookupKeyForEditor(cm, name, handle);
7188
7189 if (result == "multi")
7190 { cm.state.keySeq = name; }
7191 if (result == "handled")
7192 { signalLater(cm, "keyHandled", cm, name, e); }
7193
7194 if (result == "handled" || result == "multi") {
7195 e_preventDefault(e);
7196 restartBlink(cm);
7197 }
7198
7199 return !!result
7200 }
7201
7202 // Handle a key from the keydown event.
7203 function handleKeyBinding(cm, e) {
7204 var name = keyName(e, true);
7205 if (!name) { return false }
7206
7207 if (e.shiftKey && !cm.state.keySeq) {
7208 // First try to resolve full name (including 'Shift-'). Failing
7209 // that, see if there is a cursor-motion command (starting with
7210 // 'go') bound to the keyname without 'Shift-'.
7211 return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
7212 || dispatchKey(cm, name, e, function (b) {
7213 if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
7214 { return doHandleBinding(cm, b) }
7215 })
7216 } else {
7217 return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
7218 }
7219 }
7220
7221 // Handle a key from the keypress event
7222 function handleCharBinding(cm, e, ch) {
7223 return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
7224 }
7225
7226 var lastStoppedKey = null;
7227 function onKeyDown(e) {
7228 var cm = this;
7229 cm.curOp.focus = activeElt();
7230 if (signalDOMEvent(cm, e)) { return }
7231 // IE does strange things with escape.
7232 if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
7233 var code = e.keyCode;
7234 cm.display.shift = code == 16 || e.shiftKey;
7235 var handled = handleKeyBinding(cm, e);
7236 if (presto) {
7237 lastStoppedKey = handled ? code : null;
7238 // Opera has no cut event... we try to at least catch the key combo
7239 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
7240 { cm.replaceSelection("", null, "cut"); }
7241 }
7242
7243 // Turn mouse into crosshair when Alt is held on Mac.
7244 if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
7245 { showCrossHair(cm); }
7246 }
7247
7248 function showCrossHair(cm) {
7249 var lineDiv = cm.display.lineDiv;
7250 addClass(lineDiv, "CodeMirror-crosshair");
7251
7252 function up(e) {
7253 if (e.keyCode == 18 || !e.altKey) {
7254 rmClass(lineDiv, "CodeMirror-crosshair");
7255 off(document, "keyup", up);
7256 off(document, "mouseover", up);
7257 }
7258 }
7259 on(document, "keyup", up);
7260 on(document, "mouseover", up);
7261 }
7262
7263 function onKeyUp(e) {
7264 if (e.keyCode == 16) { this.doc.sel.shift = false; }
7265 signalDOMEvent(this, e);
7266 }
7267
7268 function onKeyPress(e) {
7269 var cm = this;
7270 if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
7271 var keyCode = e.keyCode, charCode = e.charCode;
7272 if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
7273 if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
7274 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
7275 // Some browsers fire keypress events for backspace
7276 if (ch == "\x08") { return }
7277 if (handleCharBinding(cm, e, ch)) { return }
7278 cm.display.input.onKeyPress(e);
7279 }
7280
7281 var DOUBLECLICK_DELAY = 400;
7282
7283 var PastClick = function(time, pos, button) {
7284 this.time = time;
7285 this.pos = pos;
7286 this.button = button;
7287 };
7288
7289 PastClick.prototype.compare = function (time, pos, button) {
7290 return this.time + DOUBLECLICK_DELAY > time &&
7291 cmp(pos, this.pos) == 0 && button == this.button
7292 };
7293
7294 var lastClick, lastDoubleClick;
7295 function clickRepeat(pos, button) {
7296 var now = +new Date;
7297 if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
7298 lastClick = lastDoubleClick = null;
7299 return "triple"
7300 } else if (lastClick && lastClick.compare(now, pos, button)) {
7301 lastDoubleClick = new PastClick(now, pos, button);
7302 lastClick = null;
7303 return "double"
7304 } else {
7305 lastClick = new PastClick(now, pos, button);
7306 lastDoubleClick = null;
7307 return "single"
7308 }
7309 }
7310
7311 // A mouse down can be a single click, double click, triple click,
7312 // start of selection drag, start of text drag, new cursor
7313 // (ctrl-click), rectangle drag (alt-drag), or xwin
7314 // middle-click-paste. Or it might be a click on something we should
7315 // not interfere with, such as a scrollbar or widget.
7316 function onMouseDown(e) {
7317 var cm = this, display = cm.display;
7318 if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
7319 display.input.ensurePolled();
7320 display.shift = e.shiftKey;
7321
7322 if (eventInWidget(display, e)) {
7323 if (!webkit) {
7324 // Briefly turn off draggability, to allow widgets to do
7325 // normal dragging things.
7326 display.scroller.draggable = false;
7327 setTimeout(function () { return display.scroller.draggable = true; }, 100);
7328 }
7329 return
7330 }
7331 if (clickInGutter(cm, e)) { return }
7332 var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
7333 window.focus();
7334
7335 // #3261: make sure, that we're not starting a second selection
7336 if (button == 1 && cm.state.selectingText)
7337 { cm.state.selectingText(e); }
7338
7339 if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
7340
7341 if (button == 1) {
7342 if (pos) { leftButtonDown(cm, pos, repeat, e); }
7343 else if (e_target(e) == display.scroller) { e_preventDefault(e); }
7344 } else if (button == 2) {
7345 if (pos) { extendSelection(cm.doc, pos); }
7346 setTimeout(function () { return display.input.focus(); }, 20);
7347 } else if (button == 3) {
7348 if (captureRightClick) { cm.display.input.onContextMenu(e); }
7349 else { delayBlurEvent(cm); }
7350 }
7351 }
7352
7353 function handleMappedButton(cm, button, pos, repeat, event) {
7354 var name = "Click";
7355 if (repeat == "double") { name = "Double" + name; }
7356 else if (repeat == "triple") { name = "Triple" + name; }
7357 name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
7358
7359 return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {
7360 if (typeof bound == "string") { bound = commands[bound]; }
7361 if (!bound) { return false }
7362 var done = false;
7363 try {
7364 if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
7365 done = bound(cm, pos) != Pass;
7366 } finally {
7367 cm.state.suppressEdits = false;
7368 }
7369 return done
7370 })
7371 }
7372
7373 function configureMouse(cm, repeat, event) {
7374 var option = cm.getOption("configureMouse");
7375 var value = option ? option(cm, repeat, event) : {};
7376 if (value.unit == null) {
7377 var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
7378 value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
7379 }
7380 if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
7381 if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
7382 if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
7383 return value
7384 }
7385
7386 function leftButtonDown(cm, pos, repeat, event) {
7387 if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
7388 else { cm.curOp.focus = activeElt(); }
7389
7390 var behavior = configureMouse(cm, repeat, event);
7391
7392 var sel = cm.doc.sel, contained;
7393 if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
7394 repeat == "single" && (contained = sel.contains(pos)) > -1 &&
7395 (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
7396 (cmp(contained.to(), pos) > 0 || pos.xRel < 0))
7397 { leftButtonStartDrag(cm, event, pos, behavior); }
7398 else
7399 { leftButtonSelect(cm, event, pos, behavior); }
7400 }
7401
7402 // Start a text drag. When it ends, see if any dragging actually
7403 // happen, and treat as a click if it didn't.
7404 function leftButtonStartDrag(cm, event, pos, behavior) {
7405 var display = cm.display, moved = false;
7406 var dragEnd = operation(cm, function (e) {
7407 if (webkit) { display.scroller.draggable = false; }
7408 cm.state.draggingText = false;
7409 off(display.wrapper.ownerDocument, "mouseup", dragEnd);
7410 off(display.wrapper.ownerDocument, "mousemove", mouseMove);
7411 off(display.scroller, "dragstart", dragStart);
7412 off(display.scroller, "drop", dragEnd);
7413 if (!moved) {
7414 e_preventDefault(e);
7415 if (!behavior.addNew)
7416 { extendSelection(cm.doc, pos, null, null, behavior.extend); }
7417 // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
7418 if (webkit || ie && ie_version == 9)
7419 { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); }
7420 else
7421 { display.input.focus(); }
7422 }
7423 });
7424 var mouseMove = function(e2) {
7425 moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
7426 };
7427 var dragStart = function () { return moved = true; };
7428 // Let the drag handler handle this.
7429 if (webkit) { display.scroller.draggable = true; }
7430 cm.state.draggingText = dragEnd;
7431 dragEnd.copy = !behavior.moveOnDrag;
7432 // IE's approach to draggable
7433 if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
7434 on(display.wrapper.ownerDocument, "mouseup", dragEnd);
7435 on(display.wrapper.ownerDocument, "mousemove", mouseMove);
7436 on(display.scroller, "dragstart", dragStart);
7437 on(display.scroller, "drop", dragEnd);
7438
7439 delayBlurEvent(cm);
7440 setTimeout(function () { return display.input.focus(); }, 20);
7441 }
7442
7443 function rangeForUnit(cm, pos, unit) {
7444 if (unit == "char") { return new Range(pos, pos) }
7445 if (unit == "word") { return cm.findWordAt(pos) }
7446 if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
7447 var result = unit(cm, pos);
7448 return new Range(result.from, result.to)
7449 }
7450
7451 // Normal selection, as opposed to text dragging.
7452 function leftButtonSelect(cm, event, start, behavior) {
7453 var display = cm.display, doc = cm.doc;
7454 e_preventDefault(event);
7455
7456 var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
7457 if (behavior.addNew && !behavior.extend) {
7458 ourIndex = doc.sel.contains(start);
7459 if (ourIndex > -1)
7460 { ourRange = ranges[ourIndex]; }
7461 else
7462 { ourRange = new Range(start, start); }
7463 } else {
7464 ourRange = doc.sel.primary();
7465 ourIndex = doc.sel.primIndex;
7466 }
7467
7468 if (behavior.unit == "rectangle") {
7469 if (!behavior.addNew) { ourRange = new Range(start, start); }
7470 start = posFromMouse(cm, event, true, true);
7471 ourIndex = -1;
7472 } else {
7473 var range$$1 = rangeForUnit(cm, start, behavior.unit);
7474 if (behavior.extend)
7475 { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
7476 else
7477 { ourRange = range$$1; }
7478 }
7479
7480 if (!behavior.addNew) {
7481 ourIndex = 0;
7482 setSelection(doc, new Selection([ourRange], 0), sel_mouse);
7483 startSel = doc.sel;
7484 } else if (ourIndex == -1) {
7485 ourIndex = ranges.length;
7486 setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex),
7487 {scroll: false, origin: "*mouse"});
7488 } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
7489 setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
7490 {scroll: false, origin: "*mouse"});
7491 startSel = doc.sel;
7492 } else {
7493 replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
7494 }
7495
7496 var lastPos = start;
7497 function extendTo(pos) {
7498 if (cmp(lastPos, pos) == 0) { return }
7499 lastPos = pos;
7500
7501 if (behavior.unit == "rectangle") {
7502 var ranges = [], tabSize = cm.options.tabSize;
7503 var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
7504 var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
7505 var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
7506 for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
7507 line <= end; line++) {
7508 var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
7509 if (left == right)
7510 { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
7511 else if (text.length > leftPos)
7512 { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
7513 }
7514 if (!ranges.length) { ranges.push(new Range(start, start)); }
7515 setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
7516 {origin: "*mouse", scroll: false});
7517 cm.scrollIntoView(pos);
7518 } else {
7519 var oldRange = ourRange;
7520 var range$$1 = rangeForUnit(cm, pos, behavior.unit);
7521 var anchor = oldRange.anchor, head;
7522 if (cmp(range$$1.anchor, anchor) > 0) {
7523 head = range$$1.head;
7524 anchor = minPos(oldRange.from(), range$$1.anchor);
8665 } else {
7525 } else {
8666 if (cur.from != cur.to) bidiOther = i;
7526 head = range$$1.anchor;
8667 return found;
7527 anchor = maxPos(oldRange.to(), range$$1.head);
8668 }
7528 }
8669 }
7529 var ranges$1 = startSel.ranges.slice(0);
8670 }
7530 ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
8671 return found;
7531 setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse);
8672 }
7532 }
8673
7533 }
8674 function moveInLine(line, pos, dir, byUnit) {
7534
8675 if (!byUnit) return pos + dir;
7535 var editorSize = display.wrapper.getBoundingClientRect();
8676 do pos += dir;
7536 // Used to ensure timeout re-tries don't fire when another extend
8677 while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
7537 // happened in the meantime (clearTimeout isn't reliable -- at
8678 return pos;
7538 // least on Chrome, the timeouts still happen even when cleared,
8679 }
7539 // if the clear happens after their scheduled firing time).
8680
7540 var counter = 0;
8681 // This is needed in order to move 'visually' through bi-directional
7541
8682 // text -- i.e., pressing left should make the cursor go left, even
7542 function extend(e) {
8683 // when in RTL text. The tricky part is the 'jumps', where RTL and
7543 var curCount = ++counter;
8684 // LTR text touch each other. This often requires the cursor offset
7544 var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
8685 // to move more than one unit, in order to visually move one unit.
7545 if (!cur) { return }
8686 function moveVisually(line, start, dir, byUnit) {
7546 if (cmp(cur, lastPos) != 0) {
8687 var bidi = getOrder(line);
7547 cm.curOp.focus = activeElt();
8688 if (!bidi) return moveLogically(line, start, dir, byUnit);
7548 extendTo(cur);
8689 var pos = getBidiPartAt(bidi, start), part = bidi[pos];
7549 var visible = visibleLines(display, doc);
8690 var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
7550 if (cur.line >= visible.to || cur.line < visible.from)
8691
7551 { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
8692 for (;;) {
7552 } else {
8693 if (target > part.from && target < part.to) return target;
7553 var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
8694 if (target == part.from || target == part.to) {
7554 if (outside) { setTimeout(operation(cm, function () {
8695 if (getBidiPartAt(bidi, target) == pos) return target;
7555 if (counter != curCount) { return }
8696 part = bidi[pos += dir];
7556 display.scroller.scrollTop += outside;
8697 return (dir > 0) == part.level % 2 ? part.to : part.from;
7557 extend(e);
7558 }), 50); }
7559 }
7560 }
7561
7562 function done(e) {
7563 cm.state.selectingText = false;
7564 counter = Infinity;
7565 // If e is null or undefined we interpret this as someone trying
7566 // to explicitly cancel the selection rather than the user
7567 // letting go of the mouse button.
7568 if (e) {
7569 e_preventDefault(e);
7570 display.input.focus();
7571 }
7572 off(display.wrapper.ownerDocument, "mousemove", move);
7573 off(display.wrapper.ownerDocument, "mouseup", up);
7574 doc.history.lastSelOrigin = null;
7575 }
7576
7577 var move = operation(cm, function (e) {
7578 if (e.buttons === 0 || !e_button(e)) { done(e); }
7579 else { extend(e); }
7580 });
7581 var up = operation(cm, done);
7582 cm.state.selectingText = up;
7583 on(display.wrapper.ownerDocument, "mousemove", move);
7584 on(display.wrapper.ownerDocument, "mouseup", up);
7585 }
7586
7587 // Used when mouse-selecting to adjust the anchor to the proper side
7588 // of a bidi jump depending on the visual position of the head.
7589 function bidiSimplify(cm, range$$1) {
7590 var anchor = range$$1.anchor;
7591 var head = range$$1.head;
7592 var anchorLine = getLine(cm.doc, anchor.line);
7593 if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }
7594 var order = getOrder(anchorLine);
7595 if (!order) { return range$$1 }
7596 var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
7597 if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }
7598 var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
7599 if (boundary == 0 || boundary == order.length) { return range$$1 }
7600
7601 // Compute the relative visual position of the head compared to the
7602 // anchor (<0 is to the left, >0 to the right)
7603 var leftSide;
7604 if (head.line != anchor.line) {
7605 leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0;
7606 } else {
7607 var headIndex = getBidiPartAt(order, head.ch, head.sticky);
7608 var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);
7609 if (headIndex == boundary - 1 || headIndex == boundary)
7610 { leftSide = dir < 0; }
7611 else
7612 { leftSide = dir > 0; }
7613 }
7614
7615 var usePart = order[boundary + (leftSide ? -1 : 0)];
7616 var from = leftSide == (usePart.level == 1);
7617 var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
7618 return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)
7619 }
7620
7621
7622 // Determines whether an event happened in the gutter, and fires the
7623 // handlers for the corresponding event.
7624 function gutterEvent(cm, e, type, prevent) {
7625 var mX, mY;
7626 if (e.touches) {
7627 mX = e.touches[0].clientX;
7628 mY = e.touches[0].clientY;
8698 } else {
7629 } else {
8699 part = bidi[pos += dir];
7630 try { mX = e.clientX; mY = e.clientY; }
8700 if (!part) return null;
7631 catch(e) { return false }
8701 if ((dir > 0) == part.level % 2)
7632 }
8702 target = moveInLine(line, part.to, -1, byUnit);
7633 if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
7634 if (prevent) { e_preventDefault(e); }
7635
7636 var display = cm.display;
7637 var lineBox = display.lineDiv.getBoundingClientRect();
7638
7639 if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
7640 mY -= lineBox.top - display.viewOffset;
7641
7642 for (var i = 0; i < cm.display.gutterSpecs.length; ++i) {
7643 var g = display.gutters.childNodes[i];
7644 if (g && g.getBoundingClientRect().right >= mX) {
7645 var line = lineAtHeight(cm.doc, mY);
7646 var gutter = cm.display.gutterSpecs[i];
7647 signal(cm, type, cm, line, gutter.className, e);
7648 return e_defaultPrevented(e)
7649 }
7650 }
7651 }
7652
7653 function clickInGutter(cm, e) {
7654 return gutterEvent(cm, e, "gutterClick", true)
7655 }
7656
7657 // CONTEXT MENU HANDLING
7658
7659 // To make the context menu work, we need to briefly unhide the
7660 // textarea (making it as unobtrusive as possible) to let the
7661 // right-click take effect on it.
7662 function onContextMenu(cm, e) {
7663 if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
7664 if (signalDOMEvent(cm, e, "contextmenu")) { return }
7665 if (!captureRightClick) { cm.display.input.onContextMenu(e); }
7666 }
7667
7668 function contextMenuInGutter(cm, e) {
7669 if (!hasHandler(cm, "gutterContextMenu")) { return false }
7670 return gutterEvent(cm, e, "gutterContextMenu", false)
7671 }
7672
7673 function themeChanged(cm) {
7674 cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
7675 cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
7676 clearCaches(cm);
7677 }
7678
7679 var Init = {toString: function(){return "CodeMirror.Init"}};
7680
7681 var defaults = {};
7682 var optionHandlers = {};
7683
7684 function defineOptions(CodeMirror) {
7685 var optionHandlers = CodeMirror.optionHandlers;
7686
7687 function option(name, deflt, handle, notOnInit) {
7688 CodeMirror.defaults[name] = deflt;
7689 if (handle) { optionHandlers[name] =
7690 notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
7691 }
7692
7693 CodeMirror.defineOption = option;
7694
7695 // Passed to option handlers when there is no old value.
7696 CodeMirror.Init = Init;
7697
7698 // These two are, on init, called from the constructor because they
7699 // have to be initialized before the editor can start at all.
7700 option("value", "", function (cm, val) { return cm.setValue(val); }, true);
7701 option("mode", null, function (cm, val) {
7702 cm.doc.modeOption = val;
7703 loadMode(cm);
7704 }, true);
7705
7706 option("indentUnit", 2, loadMode, true);
7707 option("indentWithTabs", false);
7708 option("smartIndent", true);
7709 option("tabSize", 4, function (cm) {
7710 resetModeState(cm);
7711 clearCaches(cm);
7712 regChange(cm);
7713 }, true);
7714
7715 option("lineSeparator", null, function (cm, val) {
7716 cm.doc.lineSep = val;
7717 if (!val) { return }
7718 var newBreaks = [], lineNo = cm.doc.first;
7719 cm.doc.iter(function (line) {
7720 for (var pos = 0;;) {
7721 var found = line.text.indexOf(val, pos);
7722 if (found == -1) { break }
7723 pos = found + val.length;
7724 newBreaks.push(Pos(lineNo, found));
7725 }
7726 lineNo++;
7727 });
7728 for (var i = newBreaks.length - 1; i >= 0; i--)
7729 { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
7730 });
7731 option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) {
7732 cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
7733 if (old != Init) { cm.refresh(); }
7734 });
7735 option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
7736 option("electricChars", true);
7737 option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
7738 throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
7739 }, true);
7740 option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
7741 option("autocorrect", false, function (cm, val) { return cm.getInputField().autocorrect = val; }, true);
7742 option("autocapitalize", false, function (cm, val) { return cm.getInputField().autocapitalize = val; }, true);
7743 option("rtlMoveVisually", !windows);
7744 option("wholeLineUpdateBefore", true);
7745
7746 option("theme", "default", function (cm) {
7747 themeChanged(cm);
7748 updateGutters(cm);
7749 }, true);
7750 option("keyMap", "default", function (cm, val, old) {
7751 var next = getKeyMap(val);
7752 var prev = old != Init && getKeyMap(old);
7753 if (prev && prev.detach) { prev.detach(cm, next); }
7754 if (next.attach) { next.attach(cm, prev || null); }
7755 });
7756 option("extraKeys", null);
7757 option("configureMouse", null);
7758
7759 option("lineWrapping", false, wrappingChanged, true);
7760 option("gutters", [], function (cm, val) {
7761 cm.display.gutterSpecs = getGutters(val, cm.options.lineNumbers);
7762 updateGutters(cm);
7763 }, true);
7764 option("fixedGutter", true, function (cm, val) {
7765 cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
7766 cm.refresh();
7767 }, true);
7768 option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
7769 option("scrollbarStyle", "native", function (cm) {
7770 initScrollbars(cm);
7771 updateScrollbars(cm);
7772 cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
7773 cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
7774 }, true);
7775 option("lineNumbers", false, function (cm, val) {
7776 cm.display.gutterSpecs = getGutters(cm.options.gutters, val);
7777 updateGutters(cm);
7778 }, true);
7779 option("firstLineNumber", 1, updateGutters, true);
7780 option("lineNumberFormatter", function (integer) { return integer; }, updateGutters, true);
7781 option("showCursorWhenSelecting", false, updateSelection, true);
7782
7783 option("resetSelectionOnContextMenu", true);
7784 option("lineWiseCopyCut", true);
7785 option("pasteLinesPerSelection", true);
7786 option("selectionsMayTouch", false);
7787
7788 option("readOnly", false, function (cm, val) {
7789 if (val == "nocursor") {
7790 onBlur(cm);
7791 cm.display.input.blur();
7792 }
7793 cm.display.input.readOnlyChanged(val);
7794 });
7795 option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
7796 option("dragDrop", true, dragDropChanged);
7797 option("allowDropFileTypes", null);
7798
7799 option("cursorBlinkRate", 530);
7800 option("cursorScrollMargin", 0);
7801 option("cursorHeight", 1, updateSelection, true);
7802 option("singleCursorHeightPerLine", true, updateSelection, true);
7803 option("workTime", 100);
7804 option("workDelay", 100);
7805 option("flattenSpans", true, resetModeState, true);
7806 option("addModeClass", false, resetModeState, true);
7807 option("pollInterval", 100);
7808 option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
7809 option("historyEventDelay", 1250);
7810 option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
7811 option("maxHighlightLength", 10000, resetModeState, true);
7812 option("moveInputWithCursor", true, function (cm, val) {
7813 if (!val) { cm.display.input.resetPosition(); }
7814 });
7815
7816 option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
7817 option("autofocus", null);
7818 option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
7819 option("phrases", null);
7820 }
7821
7822 function dragDropChanged(cm, value, old) {
7823 var wasOn = old && old != Init;
7824 if (!value != !wasOn) {
7825 var funcs = cm.display.dragFunctions;
7826 var toggle = value ? on : off;
7827 toggle(cm.display.scroller, "dragstart", funcs.start);
7828 toggle(cm.display.scroller, "dragenter", funcs.enter);
7829 toggle(cm.display.scroller, "dragover", funcs.over);
7830 toggle(cm.display.scroller, "dragleave", funcs.leave);
7831 toggle(cm.display.scroller, "drop", funcs.drop);
7832 }
7833 }
7834
7835 function wrappingChanged(cm) {
7836 if (cm.options.lineWrapping) {
7837 addClass(cm.display.wrapper, "CodeMirror-wrap");
7838 cm.display.sizer.style.minWidth = "";
7839 cm.display.sizerWidth = null;
7840 } else {
7841 rmClass(cm.display.wrapper, "CodeMirror-wrap");
7842 findMaxLine(cm);
7843 }
7844 estimateLineHeights(cm);
7845 regChange(cm);
7846 clearCaches(cm);
7847 setTimeout(function () { return updateScrollbars(cm); }, 100);
7848 }
7849
7850 // A CodeMirror instance represents an editor. This is the object
7851 // that user code is usually dealing with.
7852
7853 function CodeMirror(place, options) {
7854 var this$1 = this;
7855
7856 if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) }
7857
7858 this.options = options = options ? copyObj(options) : {};
7859 // Determine effective options based on given values and defaults.
7860 copyObj(defaults, options, false);
7861
7862 var doc = options.value;
7863 if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
7864 else if (options.mode) { doc.modeOption = options.mode; }
7865 this.doc = doc;
7866
7867 var input = new CodeMirror.inputStyles[options.inputStyle](this);
7868 var display = this.display = new Display(place, doc, input, options);
7869 display.wrapper.CodeMirror = this;
7870 themeChanged(this);
7871 if (options.lineWrapping)
7872 { this.display.wrapper.className += " CodeMirror-wrap"; }
7873 initScrollbars(this);
7874
7875 this.state = {
7876 keyMaps: [], // stores maps added by addKeyMap
7877 overlays: [], // highlighting overlays, as added by addOverlay
7878 modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
7879 overwrite: false,
7880 delayingBlurEvent: false,
7881 focused: false,
7882 suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
7883 pasteIncoming: -1, cutIncoming: -1, // help recognize paste/cut edits in input.poll
7884 selectingText: false,
7885 draggingText: false,
7886 highlight: new Delayed(), // stores highlight worker timeout
7887 keySeq: null, // Unfinished key sequence
7888 specialChars: null
7889 };
7890
7891 if (options.autofocus && !mobile) { display.input.focus(); }
7892
7893 // Override magic textarea content restore that IE sometimes does
7894 // on our hidden textarea on reload
7895 if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
7896
7897 registerEventHandlers(this);
7898 ensureGlobalHandlers();
7899
7900 startOperation(this);
7901 this.curOp.forceUpdate = true;
7902 attachDoc(this, doc);
7903
7904 if ((options.autofocus && !mobile) || this.hasFocus())
7905 { setTimeout(bind(onFocus, this), 20); }
7906 else
7907 { onBlur(this); }
7908
7909 for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
7910 { optionHandlers[opt](this$1, options[opt], Init); } }
7911 maybeUpdateLineNumberWidth(this);
7912 if (options.finishInit) { options.finishInit(this); }
7913 for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }
7914 endOperation(this);
7915 // Suppress optimizelegibility in Webkit, since it breaks text
7916 // measuring on line wrapping boundaries.
7917 if (webkit && options.lineWrapping &&
7918 getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
7919 { display.lineDiv.style.textRendering = "auto"; }
7920 }
7921
7922 // The default configuration options.
7923 CodeMirror.defaults = defaults;
7924 // Functions to run when options are changed.
7925 CodeMirror.optionHandlers = optionHandlers;
7926
7927 // Attach the necessary event handlers when initializing the editor
7928 function registerEventHandlers(cm) {
7929 var d = cm.display;
7930 on(d.scroller, "mousedown", operation(cm, onMouseDown));
7931 // Older IE's will not fire a second mousedown for a double click
7932 if (ie && ie_version < 11)
7933 { on(d.scroller, "dblclick", operation(cm, function (e) {
7934 if (signalDOMEvent(cm, e)) { return }
7935 var pos = posFromMouse(cm, e);
7936 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
7937 e_preventDefault(e);
7938 var word = cm.findWordAt(pos);
7939 extendSelection(cm.doc, word.anchor, word.head);
7940 })); }
8703 else
7941 else
8704 target = moveInLine(line, part.from, 1, byUnit);
7942 { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
8705 }
7943 // Some browsers fire contextmenu *after* opening the menu, at
8706 }
7944 // which point we can't mess with it anymore. Context menu is
8707 }
7945 // handled in onMouseDown for these browsers.
8708
7946 on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); });
8709 function moveLogically(line, start, dir, byUnit) {
7947
8710 var target = start + dir;
7948 // Used to suppress mouse event handling when a touch happens
8711 if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
7949 var touchFinished, prevTouch = {end: 0};
8712 return target < 0 || target > line.text.length ? null : target;
7950 function finishTouch() {
8713 }
7951 if (d.activeTouch) {
8714
7952 touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
8715 // Bidirectional ordering algorithm
7953 prevTouch = d.activeTouch;
8716 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
7954 prevTouch.end = +new Date;
8717 // that this (partially) implements.
7955 }
8718
7956 }
8719 // One-char codes used for character types:
7957 function isMouseLikeTouchEvent(e) {
8720 // L (L): Left-to-Right
7958 if (e.touches.length != 1) { return false }
8721 // R (R): Right-to-Left
7959 var touch = e.touches[0];
8722 // r (AL): Right-to-Left Arabic
7960 return touch.radiusX <= 1 && touch.radiusY <= 1
8723 // 1 (EN): European Number
7961 }
8724 // + (ES): European Number Separator
7962 function farAway(touch, other) {
8725 // % (ET): European Number Terminator
7963 if (other.left == null) { return true }
8726 // n (AN): Arabic Number
7964 var dx = other.left - touch.left, dy = other.top - touch.top;
8727 // , (CS): Common Number Separator
7965 return dx * dx + dy * dy > 20 * 20
8728 // m (NSM): Non-Spacing Mark
7966 }
8729 // b (BN): Boundary Neutral
7967 on(d.scroller, "touchstart", function (e) {
8730 // s (B): Paragraph Separator
7968 if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
8731 // t (S): Segment Separator
7969 d.input.ensurePolled();
8732 // w (WS): Whitespace
7970 clearTimeout(touchFinished);
8733 // N (ON): Other Neutrals
7971 var now = +new Date;
8734
7972 d.activeTouch = {start: now, moved: false,
8735 // Returns null if characters are ordered as they appear
7973 prev: now - prevTouch.end <= 300 ? prevTouch : null};
8736 // (left-to-right), or an array of sections ({from, to, level}
7974 if (e.touches.length == 1) {
8737 // objects) in the order in which they occur visually.
7975 d.activeTouch.left = e.touches[0].pageX;
8738 var bidiOrdering = (function() {
7976 d.activeTouch.top = e.touches[0].pageY;
8739 // Character types for codepoints 0 to 0xff
7977 }
8740 var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
7978 }
8741 // Character types for codepoints 0x600 to 0x6ff
7979 });
8742 var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
7980 on(d.scroller, "touchmove", function () {
8743 function charType(code) {
7981 if (d.activeTouch) { d.activeTouch.moved = true; }
8744 if (code <= 0xf7) return lowTypes.charAt(code);
7982 });
8745 else if (0x590 <= code && code <= 0x5f4) return "R";
7983 on(d.scroller, "touchend", function (e) {
8746 else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
7984 var touch = d.activeTouch;
8747 else if (0x6ee <= code && code <= 0x8ac) return "r";
7985 if (touch && !eventInWidget(d, e) && touch.left != null &&
8748 else if (0x2000 <= code && code <= 0x200b) return "w";
7986 !touch.moved && new Date - touch.start < 300) {
8749 else if (code == 0x200c) return "b";
7987 var pos = cm.coordsChar(d.activeTouch, "page"), range;
8750 else return "L";
7988 if (!touch.prev || farAway(touch, touch.prev)) // Single tap
8751 }
7989 { range = new Range(pos, pos); }
8752
7990 else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
8753 var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
7991 { range = cm.findWordAt(pos); }
8754 var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
7992 else // Triple tap
8755 // Browsers seem to always treat the boundaries of block elements as being L.
7993 { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
8756 var outerType = "L";
7994 cm.setSelection(range.anchor, range.head);
8757
7995 cm.focus();
8758 function BidiSpan(level, from, to) {
7996 e_preventDefault(e);
8759 this.level = level;
7997 }
8760 this.from = from; this.to = to;
7998 finishTouch();
8761 }
7999 });
8762
8000 on(d.scroller, "touchcancel", finishTouch);
8763 return function(str) {
8001
8764 if (!bidiRE.test(str)) return false;
8002 // Sync scrolling between fake scrollbars and real scrollable
8765 var len = str.length, types = [];
8003 // area, ensure viewport is updated when scrolling.
8766 for (var i = 0, type; i < len; ++i)
8004 on(d.scroller, "scroll", function () {
8767 types.push(type = charType(str.charCodeAt(i)));
8005 if (d.scroller.clientHeight) {
8768
8006 updateScrollTop(cm, d.scroller.scrollTop);
8769 // W1. Examine each non-spacing mark (NSM) in the level run, and
8007 setScrollLeft(cm, d.scroller.scrollLeft, true);
8770 // change the type of the NSM to the type of the previous
8008 signal(cm, "scroll", cm);
8771 // character. If the NSM is at the start of the level run, it will
8009 }
8772 // get the type of sor.
8010 });
8773 for (var i = 0, prev = outerType; i < len; ++i) {
8011
8774 var type = types[i];
8012 // Listen to wheel events in order to try and update the viewport on time.
8775 if (type == "m") types[i] = prev;
8013 on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
8776 else prev = type;
8014 on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
8777 }
8015
8778
8016 // Prevent wrapper from ever scrolling
8779 // W2. Search backwards from each instance of a European number
8017 on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
8780 // until the first strong type (R, L, AL, or sor) is found. If an
8018
8781 // AL is found, change the type of the European number to Arabic
8019 d.dragFunctions = {
8782 // number.
8020 enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
8783 // W3. Change all ALs to R.
8021 over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
8784 for (var i = 0, cur = outerType; i < len; ++i) {
8022 start: function (e) { return onDragStart(cm, e); },
8785 var type = types[i];
8023 drop: operation(cm, onDrop),
8786 if (type == "1" && cur == "r") types[i] = "n";
8024 leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
8787 else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
8025 };
8788 }
8026
8789
8027 var inp = d.input.getField();
8790 // W4. A single European separator between two European numbers
8028 on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
8791 // changes to a European number. A single common separator between
8029 on(inp, "keydown", operation(cm, onKeyDown));
8792 // two numbers of the same type changes to that type.
8030 on(inp, "keypress", operation(cm, onKeyPress));
8793 for (var i = 1, prev = types[0]; i < len - 1; ++i) {
8031 on(inp, "focus", function (e) { return onFocus(cm, e); });
8794 var type = types[i];
8032 on(inp, "blur", function (e) { return onBlur(cm, e); });
8795 if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
8033 }
8796 else if (type == "," && prev == types[i+1] &&
8034
8797 (prev == "1" || prev == "n")) types[i] = prev;
8035 var initHooks = [];
8798 prev = type;
8036 CodeMirror.defineInitHook = function (f) { return initHooks.push(f); };
8799 }
8037
8800
8038 // Indent the given line. The how parameter can be "smart",
8801 // W5. A sequence of European terminators adjacent to European
8039 // "add"/null, "subtract", or "prev". When aggressive is false
8802 // numbers changes to all European numbers.
8040 // (typically set to true for forced single-line indents), empty
8803 // W6. Otherwise, separators and terminators change to Other
8041 // lines are not indented, and places where the mode returns Pass
8804 // Neutral.
8042 // are left alone.
8805 for (var i = 0; i < len; ++i) {
8043 function indentLine(cm, n, how, aggressive) {
8806 var type = types[i];
8044 var doc = cm.doc, state;
8807 if (type == ",") types[i] = "N";
8045 if (how == null) { how = "add"; }
8808 else if (type == "%") {
8046 if (how == "smart") {
8809 for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
8047 // Fall back to "prev" when the mode doesn't have an indentation
8810 var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
8048 // method.
8811 for (var j = i; j < end; ++j) types[j] = replace;
8049 if (!doc.mode.indent) { how = "prev"; }
8812 i = end - 1;
8050 else { state = getContextBefore(cm, n).state; }
8813 }
8051 }
8814 }
8052
8815
8053 var tabSize = cm.options.tabSize;
8816 // W7. Search backwards from each instance of a European number
8054 var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
8817 // until the first strong type (R, L, or sor) is found. If an L is
8055 if (line.stateAfter) { line.stateAfter = null; }
8818 // found, then change the type of the European number to L.
8056 var curSpaceString = line.text.match(/^\s*/)[0], indentation;
8819 for (var i = 0, cur = outerType; i < len; ++i) {
8057 if (!aggressive && !/\S/.test(line.text)) {
8820 var type = types[i];
8058 indentation = 0;
8821 if (cur == "L" && type == "1") types[i] = "L";
8059 how = "not";
8822 else if (isStrong.test(type)) cur = type;
8060 } else if (how == "smart") {
8823 }
8061 indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
8824
8062 if (indentation == Pass || indentation > 150) {
8825 // N1. A sequence of neutrals takes the direction of the
8063 if (!aggressive) { return }
8826 // surrounding strong text if the text on both sides has the same
8064 how = "prev";
8827 // direction. European and Arabic numbers act as if they were R in
8065 }
8828 // terms of their influence on neutrals. Start-of-level-run (sor)
8066 }
8829 // and end-of-level-run (eor) are used at level run boundaries.
8067 if (how == "prev") {
8830 // N2. Any remaining neutrals take the embedding direction.
8068 if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
8831 for (var i = 0; i < len; ++i) {
8069 else { indentation = 0; }
8832 if (isNeutral.test(types[i])) {
8070 } else if (how == "add") {
8833 for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
8071 indentation = curSpace + cm.options.indentUnit;
8834 var before = (i ? types[i-1] : outerType) == "L";
8072 } else if (how == "subtract") {
8835 var after = (end < len ? types[end] : outerType) == "L";
8073 indentation = curSpace - cm.options.indentUnit;
8836 var replace = before || after ? "L" : "R";
8074 } else if (typeof how == "number") {
8837 for (var j = i; j < end; ++j) types[j] = replace;
8075 indentation = curSpace + how;
8838 i = end - 1;
8076 }
8839 }
8077 indentation = Math.max(0, indentation);
8840 }
8078
8841
8079 var indentString = "", pos = 0;
8842 // Here we depart from the documented algorithm, in order to avoid
8080 if (cm.options.indentWithTabs)
8843 // building up an actual levels array. Since there are only three
8081 { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
8844 // levels (0, 1, 2) in an implementation that doesn't take
8082 if (pos < indentation) { indentString += spaceStr(indentation - pos); }
8845 // explicit embedding into account, we can build up the order on
8083
8846 // the fly, without following the level-based algorithm.
8084 if (indentString != curSpaceString) {
8847 var order = [], m;
8085 replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
8848 for (var i = 0; i < len;) {
8086 line.stateAfter = null;
8849 if (countsAsLeft.test(types[i])) {
8087 return true
8850 var start = i;
8088 } else {
8851 for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
8089 // Ensure that, if the cursor was in the whitespace at the start
8852 order.push(new BidiSpan(0, start, i));
8090 // of the line, it is moved to the end of that space.
8091 for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
8092 var range = doc.sel.ranges[i$1];
8093 if (range.head.line == n && range.head.ch < curSpaceString.length) {
8094 var pos$1 = Pos(n, curSpaceString.length);
8095 replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
8096 break
8097 }
8098 }
8099 }
8100 }
8101
8102 // This will be set to a {lineWise: bool, text: [string]} object, so
8103 // that, when pasting, we know what kind of selections the copied
8104 // text was made out of.
8105 var lastCopied = null;
8106
8107 function setLastCopied(newLastCopied) {
8108 lastCopied = newLastCopied;
8109 }
8110
8111 function applyTextInput(cm, inserted, deleted, sel, origin) {
8112 var doc = cm.doc;
8113 cm.display.shift = false;
8114 if (!sel) { sel = doc.sel; }
8115
8116 var recent = +new Date - 200;
8117 var paste = origin == "paste" || cm.state.pasteIncoming > recent;
8118 var textLines = splitLinesAuto(inserted), multiPaste = null;
8119 // When pasting N lines into N selections, insert one line per selection
8120 if (paste && sel.ranges.length > 1) {
8121 if (lastCopied && lastCopied.text.join("\n") == inserted) {
8122 if (sel.ranges.length % lastCopied.text.length == 0) {
8123 multiPaste = [];
8124 for (var i = 0; i < lastCopied.text.length; i++)
8125 { multiPaste.push(doc.splitLines(lastCopied.text[i])); }
8126 }
8127 } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
8128 multiPaste = map(textLines, function (l) { return [l]; });
8129 }
8130 }
8131
8132 var updateInput = cm.curOp.updateInput;
8133 // Normal behavior is to insert the new text into every selection
8134 for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
8135 var range$$1 = sel.ranges[i$1];
8136 var from = range$$1.from(), to = range$$1.to();
8137 if (range$$1.empty()) {
8138 if (deleted && deleted > 0) // Handle deletion
8139 { from = Pos(from.line, from.ch - deleted); }
8140 else if (cm.state.overwrite && !paste) // Handle overwrite
8141 { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
8142 else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
8143 { from = to = Pos(from.line, 0); }
8144 }
8145 var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
8146 origin: origin || (paste ? "paste" : cm.state.cutIncoming > recent ? "cut" : "+input")};
8147 makeChange(cm.doc, changeEvent);
8148 signalLater(cm, "inputRead", cm, changeEvent);
8149 }
8150 if (inserted && !paste)
8151 { triggerElectric(cm, inserted); }
8152
8153 ensureCursorVisible(cm);
8154 if (cm.curOp.updateInput < 2) { cm.curOp.updateInput = updateInput; }
8155 cm.curOp.typing = true;
8156 cm.state.pasteIncoming = cm.state.cutIncoming = -1;
8157 }
8158
8159 function handlePaste(e, cm) {
8160 var pasted = e.clipboardData && e.clipboardData.getData("Text");
8161 if (pasted) {
8162 e.preventDefault();
8163 if (!cm.isReadOnly() && !cm.options.disableInput)
8164 { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
8165 return true
8166 }
8167 }
8168
8169 function triggerElectric(cm, inserted) {
8170 // When an 'electric' character is inserted, immediately trigger a reindent
8171 if (!cm.options.electricChars || !cm.options.smartIndent) { return }
8172 var sel = cm.doc.sel;
8173
8174 for (var i = sel.ranges.length - 1; i >= 0; i--) {
8175 var range$$1 = sel.ranges[i];
8176 if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
8177 var mode = cm.getModeAt(range$$1.head);
8178 var indented = false;
8179 if (mode.electricChars) {
8180 for (var j = 0; j < mode.electricChars.length; j++)
8181 { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
8182 indented = indentLine(cm, range$$1.head.line, "smart");
8183 break
8184 } }
8185 } else if (mode.electricInput) {
8186 if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
8187 { indented = indentLine(cm, range$$1.head.line, "smart"); }
8188 }
8189 if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
8190 }
8191 }
8192
8193 function copyableRanges(cm) {
8194 var text = [], ranges = [];
8195 for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
8196 var line = cm.doc.sel.ranges[i].head.line;
8197 var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
8198 ranges.push(lineRange);
8199 text.push(cm.getRange(lineRange.anchor, lineRange.head));
8200 }
8201 return {text: text, ranges: ranges}
8202 }
8203
8204 function disableBrowserMagic(field, spellcheck, autocorrect, autocapitalize) {
8205 field.setAttribute("autocorrect", autocorrect ? "" : "off");
8206 field.setAttribute("autocapitalize", autocapitalize ? "" : "off");
8207 field.setAttribute("spellcheck", !!spellcheck);
8208 }
8209
8210 function hiddenTextarea() {
8211 var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
8212 var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
8213 // The textarea is kept positioned near the cursor to prevent the
8214 // fact that it'll be scrolled into view on input from scrolling
8215 // our fake cursor out of view. On webkit, when wrap=off, paste is
8216 // very slow. So make the area wide instead.
8217 if (webkit) { te.style.width = "1000px"; }
8218 else { te.setAttribute("wrap", "off"); }
8219 // If border: 0; -- iOS fails to open keyboard (issue #1287)
8220 if (ios) { te.style.border = "1px solid black"; }
8221 disableBrowserMagic(te);
8222 return div
8223 }
8224
8225 // The publicly visible API. Note that methodOp(f) means
8226 // 'wrap f in an operation, performed on its `this` parameter'.
8227
8228 // This is not the complete set of editor methods. Most of the
8229 // methods defined on the Doc type are also injected into
8230 // CodeMirror.prototype, for backwards compatibility and
8231 // convenience.
8232
8233 function addEditorMethods(CodeMirror) {
8234 var optionHandlers = CodeMirror.optionHandlers;
8235
8236 var helpers = CodeMirror.helpers = {};
8237
8238 CodeMirror.prototype = {
8239 constructor: CodeMirror,
8240 focus: function(){window.focus(); this.display.input.focus();},
8241
8242 setOption: function(option, value) {
8243 var options = this.options, old = options[option];
8244 if (options[option] == value && option != "mode") { return }
8245 options[option] = value;
8246 if (optionHandlers.hasOwnProperty(option))
8247 { operation(this, optionHandlers[option])(this, value, old); }
8248 signal(this, "optionChange", this, option);
8249 },
8250
8251 getOption: function(option) {return this.options[option]},
8252 getDoc: function() {return this.doc},
8253
8254 addKeyMap: function(map$$1, bottom) {
8255 this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
8256 },
8257 removeKeyMap: function(map$$1) {
8258 var maps = this.state.keyMaps;
8259 for (var i = 0; i < maps.length; ++i)
8260 { if (maps[i] == map$$1 || maps[i].name == map$$1) {
8261 maps.splice(i, 1);
8262 return true
8263 } }
8264 },
8265
8266 addOverlay: methodOp(function(spec, options) {
8267 var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
8268 if (mode.startState) { throw new Error("Overlays may not be stateful.") }
8269 insertSorted(this.state.overlays,
8270 {mode: mode, modeSpec: spec, opaque: options && options.opaque,
8271 priority: (options && options.priority) || 0},
8272 function (overlay) { return overlay.priority; });
8273 this.state.modeGen++;
8274 regChange(this);
8275 }),
8276 removeOverlay: methodOp(function(spec) {
8277 var this$1 = this;
8278
8279 var overlays = this.state.overlays;
8280 for (var i = 0; i < overlays.length; ++i) {
8281 var cur = overlays[i].modeSpec;
8282 if (cur == spec || typeof spec == "string" && cur.name == spec) {
8283 overlays.splice(i, 1);
8284 this$1.state.modeGen++;
8285 regChange(this$1);
8286 return
8287 }
8288 }
8289 }),
8290
8291 indentLine: methodOp(function(n, dir, aggressive) {
8292 if (typeof dir != "string" && typeof dir != "number") {
8293 if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
8294 else { dir = dir ? "add" : "subtract"; }
8295 }
8296 if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
8297 }),
8298 indentSelection: methodOp(function(how) {
8299 var this$1 = this;
8300
8301 var ranges = this.doc.sel.ranges, end = -1;
8302 for (var i = 0; i < ranges.length; i++) {
8303 var range$$1 = ranges[i];
8304 if (!range$$1.empty()) {
8305 var from = range$$1.from(), to = range$$1.to();
8306 var start = Math.max(end, from.line);
8307 end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
8308 for (var j = start; j < end; ++j)
8309 { indentLine(this$1, j, how); }
8310 var newRanges = this$1.doc.sel.ranges;
8311 if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
8312 { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
8313 } else if (range$$1.head.line > end) {
8314 indentLine(this$1, range$$1.head.line, how, true);
8315 end = range$$1.head.line;
8316 if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }
8317 }
8318 }
8319 }),
8320
8321 // Fetch the parser token for a given character. Useful for hacks
8322 // that want to inspect the mode state (say, for completion).
8323 getTokenAt: function(pos, precise) {
8324 return takeToken(this, pos, precise)
8325 },
8326
8327 getLineTokens: function(line, precise) {
8328 return takeToken(this, Pos(line), precise, true)
8329 },
8330
8331 getTokenTypeAt: function(pos) {
8332 pos = clipPos(this.doc, pos);
8333 var styles = getLineStyles(this, getLine(this.doc, pos.line));
8334 var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
8335 var type;
8336 if (ch == 0) { type = styles[2]; }
8337 else { for (;;) {
8338 var mid = (before + after) >> 1;
8339 if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
8340 else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
8341 else { type = styles[mid * 2 + 2]; break }
8342 } }
8343 var cut = type ? type.indexOf("overlay ") : -1;
8344 return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
8345 },
8346
8347 getModeAt: function(pos) {
8348 var mode = this.doc.mode;
8349 if (!mode.innerMode) { return mode }
8350 return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
8351 },
8352
8353 getHelper: function(pos, type) {
8354 return this.getHelpers(pos, type)[0]
8355 },
8356
8357 getHelpers: function(pos, type) {
8358 var this$1 = this;
8359
8360 var found = [];
8361 if (!helpers.hasOwnProperty(type)) { return found }
8362 var help = helpers[type], mode = this.getModeAt(pos);
8363 if (typeof mode[type] == "string") {
8364 if (help[mode[type]]) { found.push(help[mode[type]]); }
8365 } else if (mode[type]) {
8366 for (var i = 0; i < mode[type].length; i++) {
8367 var val = help[mode[type][i]];
8368 if (val) { found.push(val); }
8369 }
8370 } else if (mode.helperType && help[mode.helperType]) {
8371 found.push(help[mode.helperType]);
8372 } else if (help[mode.name]) {
8373 found.push(help[mode.name]);
8374 }
8375 for (var i$1 = 0; i$1 < help._global.length; i$1++) {
8376 var cur = help._global[i$1];
8377 if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
8378 { found.push(cur.val); }
8379 }
8380 return found
8381 },
8382
8383 getStateAfter: function(line, precise) {
8384 var doc = this.doc;
8385 line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
8386 return getContextBefore(this, line + 1, precise).state
8387 },
8388
8389 cursorCoords: function(start, mode) {
8390 var pos, range$$1 = this.doc.sel.primary();
8391 if (start == null) { pos = range$$1.head; }
8392 else if (typeof start == "object") { pos = clipPos(this.doc, start); }
8393 else { pos = start ? range$$1.from() : range$$1.to(); }
8394 return cursorCoords(this, pos, mode || "page")
8395 },
8396
8397 charCoords: function(pos, mode) {
8398 return charCoords(this, clipPos(this.doc, pos), mode || "page")
8399 },
8400
8401 coordsChar: function(coords, mode) {
8402 coords = fromCoordSystem(this, coords, mode || "page");
8403 return coordsChar(this, coords.left, coords.top)
8404 },
8405
8406 lineAtHeight: function(height, mode) {
8407 height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
8408 return lineAtHeight(this.doc, height + this.display.viewOffset)
8409 },
8410 heightAtLine: function(line, mode, includeWidgets) {
8411 var end = false, lineObj;
8412 if (typeof line == "number") {
8413 var last = this.doc.first + this.doc.size - 1;
8414 if (line < this.doc.first) { line = this.doc.first; }
8415 else if (line > last) { line = last; end = true; }
8416 lineObj = getLine(this.doc, line);
8417 } else {
8418 lineObj = line;
8419 }
8420 return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
8421 (end ? this.doc.height - heightAtLine(lineObj) : 0)
8422 },
8423
8424 defaultTextHeight: function() { return textHeight(this.display) },
8425 defaultCharWidth: function() { return charWidth(this.display) },
8426
8427 getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
8428
8429 addWidget: function(pos, node, scroll, vert, horiz) {
8430 var display = this.display;
8431 pos = cursorCoords(this, clipPos(this.doc, pos));
8432 var top = pos.bottom, left = pos.left;
8433 node.style.position = "absolute";
8434 node.setAttribute("cm-ignore-events", "true");
8435 this.display.input.setUneditable(node);
8436 display.sizer.appendChild(node);
8437 if (vert == "over") {
8438 top = pos.top;
8439 } else if (vert == "above" || vert == "near") {
8440 var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
8441 hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
8442 // Default to positioning above (if specified and possible); otherwise default to positioning below
8443 if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
8444 { top = pos.top - node.offsetHeight; }
8445 else if (pos.bottom + node.offsetHeight <= vspace)
8446 { top = pos.bottom; }
8447 if (left + node.offsetWidth > hspace)
8448 { left = hspace - node.offsetWidth; }
8449 }
8450 node.style.top = top + "px";
8451 node.style.left = node.style.right = "";
8452 if (horiz == "right") {
8453 left = display.sizer.clientWidth - node.offsetWidth;
8454 node.style.right = "0px";
8455 } else {
8456 if (horiz == "left") { left = 0; }
8457 else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
8458 node.style.left = left + "px";
8459 }
8460 if (scroll)
8461 { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
8462 },
8463
8464 triggerOnKeyDown: methodOp(onKeyDown),
8465 triggerOnKeyPress: methodOp(onKeyPress),
8466 triggerOnKeyUp: onKeyUp,
8467 triggerOnMouseDown: methodOp(onMouseDown),
8468
8469 execCommand: function(cmd) {
8470 if (commands.hasOwnProperty(cmd))
8471 { return commands[cmd].call(null, this) }
8472 },
8473
8474 triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
8475
8476 findPosH: function(from, amount, unit, visually) {
8477 var this$1 = this;
8478
8479 var dir = 1;
8480 if (amount < 0) { dir = -1; amount = -amount; }
8481 var cur = clipPos(this.doc, from);
8482 for (var i = 0; i < amount; ++i) {
8483 cur = findPosH(this$1.doc, cur, dir, unit, visually);
8484 if (cur.hitSide) { break }
8485 }
8486 return cur
8487 },
8488
8489 moveH: methodOp(function(dir, unit) {
8490 var this$1 = this;
8491
8492 this.extendSelectionsBy(function (range$$1) {
8493 if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
8494 { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
8495 else
8496 { return dir < 0 ? range$$1.from() : range$$1.to() }
8497 }, sel_move);
8498 }),
8499
8500 deleteH: methodOp(function(dir, unit) {
8501 var sel = this.doc.sel, doc = this.doc;
8502 if (sel.somethingSelected())
8503 { doc.replaceSelection("", null, "+delete"); }
8504 else
8505 { deleteNearSelection(this, function (range$$1) {
8506 var other = findPosH(doc, range$$1.head, dir, unit, false);
8507 return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
8508 }); }
8509 }),
8510
8511 findPosV: function(from, amount, unit, goalColumn) {
8512 var this$1 = this;
8513
8514 var dir = 1, x = goalColumn;
8515 if (amount < 0) { dir = -1; amount = -amount; }
8516 var cur = clipPos(this.doc, from);
8517 for (var i = 0; i < amount; ++i) {
8518 var coords = cursorCoords(this$1, cur, "div");
8519 if (x == null) { x = coords.left; }
8520 else { coords.left = x; }
8521 cur = findPosV(this$1, coords, dir, unit);
8522 if (cur.hitSide) { break }
8523 }
8524 return cur
8525 },
8526
8527 moveV: methodOp(function(dir, unit) {
8528 var this$1 = this;
8529
8530 var doc = this.doc, goals = [];
8531 var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
8532 doc.extendSelectionsBy(function (range$$1) {
8533 if (collapse)
8534 { return dir < 0 ? range$$1.from() : range$$1.to() }
8535 var headPos = cursorCoords(this$1, range$$1.head, "div");
8536 if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
8537 goals.push(headPos.left);
8538 var pos = findPosV(this$1, headPos, dir, unit);
8539 if (unit == "page" && range$$1 == doc.sel.primary())
8540 { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
8541 return pos
8542 }, sel_move);
8543 if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
8544 { doc.sel.ranges[i].goalColumn = goals[i]; } }
8545 }),
8546
8547 // Find the word at the given position (as returned by coordsChar).
8548 findWordAt: function(pos) {
8549 var doc = this.doc, line = getLine(doc, pos.line).text;
8550 var start = pos.ch, end = pos.ch;
8551 if (line) {
8552 var helper = this.getHelper(pos, "wordChars");
8553 if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
8554 var startChar = line.charAt(start);
8555 var check = isWordChar(startChar, helper)
8556 ? function (ch) { return isWordChar(ch, helper); }
8557 : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
8558 : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
8559 while (start > 0 && check(line.charAt(start - 1))) { --start; }
8560 while (end < line.length && check(line.charAt(end))) { ++end; }
8561 }
8562 return new Range(Pos(pos.line, start), Pos(pos.line, end))
8563 },
8564
8565 toggleOverwrite: function(value) {
8566 if (value != null && value == this.state.overwrite) { return }
8567 if (this.state.overwrite = !this.state.overwrite)
8568 { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
8569 else
8570 { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
8571
8572 signal(this, "overwriteToggle", this, this.state.overwrite);
8573 },
8574 hasFocus: function() { return this.display.input.getField() == activeElt() },
8575 isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
8576
8577 scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
8578 getScrollInfo: function() {
8579 var scroller = this.display.scroller;
8580 return {left: scroller.scrollLeft, top: scroller.scrollTop,
8581 height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
8582 width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
8583 clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
8584 },
8585
8586 scrollIntoView: methodOp(function(range$$1, margin) {
8587 if (range$$1 == null) {
8588 range$$1 = {from: this.doc.sel.primary().head, to: null};
8589 if (margin == null) { margin = this.options.cursorScrollMargin; }
8590 } else if (typeof range$$1 == "number") {
8591 range$$1 = {from: Pos(range$$1, 0), to: null};
8592 } else if (range$$1.from == null) {
8593 range$$1 = {from: range$$1, to: null};
8594 }
8595 if (!range$$1.to) { range$$1.to = range$$1.from; }
8596 range$$1.margin = margin || 0;
8597
8598 if (range$$1.from.line != null) {
8599 scrollToRange(this, range$$1);
8600 } else {
8601 scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
8602 }
8603 }),
8604
8605 setSize: methodOp(function(width, height) {
8606 var this$1 = this;
8607
8608 var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
8609 if (width != null) { this.display.wrapper.style.width = interpret(width); }
8610 if (height != null) { this.display.wrapper.style.height = interpret(height); }
8611 if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
8612 var lineNo$$1 = this.display.viewFrom;
8613 this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
8614 if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
8615 { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
8616 ++lineNo$$1;
8617 });
8618 this.curOp.forceUpdate = true;
8619 signal(this, "refresh", this);
8620 }),
8621
8622 operation: function(f){return runInOp(this, f)},
8623 startOperation: function(){return startOperation(this)},
8624 endOperation: function(){return endOperation(this)},
8625
8626 refresh: methodOp(function() {
8627 var oldHeight = this.display.cachedTextHeight;
8628 regChange(this);
8629 this.curOp.forceUpdate = true;
8630 clearCaches(this);
8631 scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
8632 updateGutterSpace(this.display);
8633 if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
8634 { estimateLineHeights(this); }
8635 signal(this, "refresh", this);
8636 }),
8637
8638 swapDoc: methodOp(function(doc) {
8639 var old = this.doc;
8640 old.cm = null;
8641 // Cancel the current text selection if any (#5821)
8642 if (this.state.selectingText) { this.state.selectingText(); }
8643 attachDoc(this, doc);
8644 clearCaches(this);
8645 this.display.input.reset();
8646 scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
8647 this.curOp.forceScroll = true;
8648 signalLater(this, "swapDoc", this, old);
8649 return old
8650 }),
8651
8652 phrase: function(phraseText) {
8653 var phrases = this.options.phrases;
8654 return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText
8655 },
8656
8657 getInputField: function(){return this.display.input.getField()},
8658 getWrapperElement: function(){return this.display.wrapper},
8659 getScrollerElement: function(){return this.display.scroller},
8660 getGutterElement: function(){return this.display.gutters}
8661 };
8662 eventMixin(CodeMirror);
8663
8664 CodeMirror.registerHelper = function(type, name, value) {
8665 if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
8666 helpers[type][name] = value;
8667 };
8668 CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
8669 CodeMirror.registerHelper(type, name, value);
8670 helpers[type]._global.push({pred: predicate, val: value});
8671 };
8672 }
8673
8674 // Used for horizontal relative motion. Dir is -1 or 1 (left or
8675 // right), unit can be "char", "column" (like char, but doesn't
8676 // cross line boundaries), "word" (across next word), or "group" (to
8677 // the start of next group of word or non-word-non-whitespace
8678 // chars). The visually param controls whether, in right-to-left
8679 // text, direction 1 means to move towards the next index in the
8680 // string, or towards the character to the right of the current
8681 // position. The resulting position will have a hitSide=true
8682 // property if it reached the end of the document.
8683 function findPosH(doc, pos, dir, unit, visually) {
8684 var oldPos = pos;
8685 var origDir = dir;
8686 var lineObj = getLine(doc, pos.line);
8687 function findNextLine() {
8688 var l = pos.line + dir;
8689 if (l < doc.first || l >= doc.first + doc.size) { return false }
8690 pos = new Pos(l, pos.ch, pos.sticky);
8691 return lineObj = getLine(doc, l)
8692 }
8693 function moveOnce(boundToLine) {
8694 var next;
8695 if (visually) {
8696 next = moveVisually(doc.cm, lineObj, pos, dir);
8697 } else {
8698 next = moveLogically(lineObj, pos, dir);
8699 }
8700 if (next == null) {
8701 if (!boundToLine && findNextLine())
8702 { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
8703 else
8704 { return false }
8705 } else {
8706 pos = next;
8707 }
8708 return true
8709 }
8710
8711 if (unit == "char") {
8712 moveOnce();
8713 } else if (unit == "column") {
8714 moveOnce(true);
8715 } else if (unit == "word" || unit == "group") {
8716 var sawType = null, group = unit == "group";
8717 var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
8718 for (var first = true;; first = false) {
8719 if (dir < 0 && !moveOnce(!first)) { break }
8720 var cur = lineObj.text.charAt(pos.ch) || "\n";
8721 var type = isWordChar(cur, helper) ? "w"
8722 : group && cur == "\n" ? "n"
8723 : !group || /\s/.test(cur) ? null
8724 : "p";
8725 if (group && !first && !type) { type = "s"; }
8726 if (sawType && sawType != type) {
8727 if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
8728 break
8729 }
8730
8731 if (type) { sawType = type; }
8732 if (dir > 0 && !moveOnce(!first)) { break }
8733 }
8734 }
8735 var result = skipAtomic(doc, pos, oldPos, origDir, true);
8736 if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
8737 return result
8738 }
8739
8740 // For relative vertical movement. Dir may be -1 or 1. Unit can be
8741 // "page" or "line". The resulting position will have a hitSide=true
8742 // property if it reached the end of the document.
8743 function findPosV(cm, pos, dir, unit) {
8744 var doc = cm.doc, x = pos.left, y;
8745 if (unit == "page") {
8746 var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
8747 var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
8748 y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
8749
8750 } else if (unit == "line") {
8751 y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
8752 }
8753 var target;
8754 for (;;) {
8755 target = coordsChar(cm, x, y);
8756 if (!target.outside) { break }
8757 if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
8758 y += dir * 5;
8759 }
8760 return target
8761 }
8762
8763 // CONTENTEDITABLE INPUT STYLE
8764
8765 var ContentEditableInput = function(cm) {
8766 this.cm = cm;
8767 this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
8768 this.polling = new Delayed();
8769 this.composing = null;
8770 this.gracePeriod = false;
8771 this.readDOMTimeout = null;
8772 };
8773
8774 ContentEditableInput.prototype.init = function (display) {
8775 var this$1 = this;
8776
8777 var input = this, cm = input.cm;
8778 var div = input.div = display.lineDiv;
8779 disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize);
8780
8781 on(div, "paste", function (e) {
8782 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
8783 // IE doesn't fire input events, so we schedule a read for the pasted content in this way
8784 if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
8785 });
8786
8787 on(div, "compositionstart", function (e) {
8788 this$1.composing = {data: e.data, done: false};
8789 });
8790 on(div, "compositionupdate", function (e) {
8791 if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
8792 });
8793 on(div, "compositionend", function (e) {
8794 if (this$1.composing) {
8795 if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
8796 this$1.composing.done = true;
8797 }
8798 });
8799
8800 on(div, "touchstart", function () { return input.forceCompositionEnd(); });
8801
8802 on(div, "input", function () {
8803 if (!this$1.composing) { this$1.readFromDOMSoon(); }
8804 });
8805
8806 function onCopyCut(e) {
8807 if (signalDOMEvent(cm, e)) { return }
8808 if (cm.somethingSelected()) {
8809 setLastCopied({lineWise: false, text: cm.getSelections()});
8810 if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
8811 } else if (!cm.options.lineWiseCopyCut) {
8812 return
8853 } else {
8813 } else {
8854 var pos = i, at = order.length;
8814 var ranges = copyableRanges(cm);
8855 for (++i; i < len && types[i] != "L"; ++i) {}
8815 setLastCopied({lineWise: true, text: ranges.text});
8856 for (var j = pos; j < i;) {
8816 if (e.type == "cut") {
8857 if (countsAsNum.test(types[j])) {
8817 cm.operation(function () {
8858 if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
8818 cm.setSelections(ranges.ranges, 0, sel_dontScroll);
8859 var nstart = j;
8819 cm.replaceSelection("", null, "cut");
8860 for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
8820 });
8861 order.splice(at, 0, new BidiSpan(2, nstart, j));
8821 }
8862 pos = j;
8822 }
8863 } else ++j;
8823 if (e.clipboardData) {
8864 }
8824 e.clipboardData.clearData();
8865 if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
8825 var content = lastCopied.text.join("\n");
8866 }
8826 // iOS exposes the clipboard API, but seems to discard content inserted into it
8867 }
8827 e.clipboardData.setData("Text", content);
8868 if (order[0].level == 1 && (m = str.match(/^\s+/))) {
8828 if (e.clipboardData.getData("Text") == content) {
8869 order[0].from = m[0].length;
8829 e.preventDefault();
8870 order.unshift(new BidiSpan(0, 0, m[0].length));
8830 return
8871 }
8831 }
8872 if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
8832 }
8873 lst(order).to -= m[0].length;
8833 // Old-fashioned briefly-focus-a-textarea hack
8874 order.push(new BidiSpan(0, len - m[0].length, len));
8834 var kludge = hiddenTextarea(), te = kludge.firstChild;
8875 }
8835 cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
8876 if (order[0].level == 2)
8836 te.value = lastCopied.text.join("\n");
8877 order.unshift(new BidiSpan(1, order[0].to, order[0].to));
8837 var hadFocus = document.activeElement;
8878 if (order[0].level != lst(order).level)
8838 selectInput(te);
8879 order.push(new BidiSpan(order[0].level, len, len));
8839 setTimeout(function () {
8880
8840 cm.display.lineSpace.removeChild(kludge);
8881 return order;
8841 hadFocus.focus();
8882 };
8842 if (hadFocus == div) { input.showPrimarySelection(); }
8883 })();
8843 }, 50);
8884
8844 }
8885 // THE END
8845 on(div, "copy", onCopyCut);
8886
8846 on(div, "cut", onCopyCut);
8887 CodeMirror.version = "5.11.0";
8847 };
8848
8849 ContentEditableInput.prototype.prepareSelection = function () {
8850 var result = prepareSelection(this.cm, false);
8851 result.focus = this.cm.state.focused;
8852 return result
8853 };
8854
8855 ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
8856 if (!info || !this.cm.display.view.length) { return }
8857 if (info.focus || takeFocus) { this.showPrimarySelection(); }
8858 this.showMultipleSelections(info);
8859 };
8860
8861 ContentEditableInput.prototype.getSelection = function () {
8862 return this.cm.display.wrapper.ownerDocument.getSelection()
8863 };
8864
8865 ContentEditableInput.prototype.showPrimarySelection = function () {
8866 var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
8867 var from = prim.from(), to = prim.to();
8868
8869 if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
8870 sel.removeAllRanges();
8871 return
8872 }
8873
8874 var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
8875 var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
8876 if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
8877 cmp(minPos(curAnchor, curFocus), from) == 0 &&
8878 cmp(maxPos(curAnchor, curFocus), to) == 0)
8879 { return }
8880
8881 var view = cm.display.view;
8882 var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
8883 {node: view[0].measure.map[2], offset: 0};
8884 var end = to.line < cm.display.viewTo && posToDOM(cm, to);
8885 if (!end) {
8886 var measure = view[view.length - 1].measure;
8887 var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
8888 end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
8889 }
8890
8891 if (!start || !end) {
8892 sel.removeAllRanges();
8893 return
8894 }
8895
8896 var old = sel.rangeCount && sel.getRangeAt(0), rng;
8897 try { rng = range(start.node, start.offset, end.offset, end.node); }
8898 catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
8899 if (rng) {
8900 if (!gecko && cm.state.focused) {
8901 sel.collapse(start.node, start.offset);
8902 if (!rng.collapsed) {
8903 sel.removeAllRanges();
8904 sel.addRange(rng);
8905 }
8906 } else {
8907 sel.removeAllRanges();
8908 sel.addRange(rng);
8909 }
8910 if (old && sel.anchorNode == null) { sel.addRange(old); }
8911 else if (gecko) { this.startGracePeriod(); }
8912 }
8913 this.rememberSelection();
8914 };
8915
8916 ContentEditableInput.prototype.startGracePeriod = function () {
8917 var this$1 = this;
8918
8919 clearTimeout(this.gracePeriod);
8920 this.gracePeriod = setTimeout(function () {
8921 this$1.gracePeriod = false;
8922 if (this$1.selectionChanged())
8923 { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
8924 }, 20);
8925 };
8926
8927 ContentEditableInput.prototype.showMultipleSelections = function (info) {
8928 removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
8929 removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
8930 };
8931
8932 ContentEditableInput.prototype.rememberSelection = function () {
8933 var sel = this.getSelection();
8934 this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
8935 this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
8936 };
8937
8938 ContentEditableInput.prototype.selectionInEditor = function () {
8939 var sel = this.getSelection();
8940 if (!sel.rangeCount) { return false }
8941 var node = sel.getRangeAt(0).commonAncestorContainer;
8942 return contains(this.div, node)
8943 };
8944
8945 ContentEditableInput.prototype.focus = function () {
8946 if (this.cm.options.readOnly != "nocursor") {
8947 if (!this.selectionInEditor())
8948 { this.showSelection(this.prepareSelection(), true); }
8949 this.div.focus();
8950 }
8951 };
8952 ContentEditableInput.prototype.blur = function () { this.div.blur(); };
8953 ContentEditableInput.prototype.getField = function () { return this.div };
8954
8955 ContentEditableInput.prototype.supportsTouch = function () { return true };
8956
8957 ContentEditableInput.prototype.receivedFocus = function () {
8958 var input = this;
8959 if (this.selectionInEditor())
8960 { this.pollSelection(); }
8961 else
8962 { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
8963
8964 function poll() {
8965 if (input.cm.state.focused) {
8966 input.pollSelection();
8967 input.polling.set(input.cm.options.pollInterval, poll);
8968 }
8969 }
8970 this.polling.set(this.cm.options.pollInterval, poll);
8971 };
8972
8973 ContentEditableInput.prototype.selectionChanged = function () {
8974 var sel = this.getSelection();
8975 return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
8976 sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
8977 };
8978
8979 ContentEditableInput.prototype.pollSelection = function () {
8980 if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
8981 var sel = this.getSelection(), cm = this.cm;
8982 // On Android Chrome (version 56, at least), backspacing into an
8983 // uneditable block element will put the cursor in that element,
8984 // and then, because it's not editable, hide the virtual keyboard.
8985 // Because Android doesn't allow us to actually detect backspace
8986 // presses in a sane way, this code checks for when that happens
8987 // and simulates a backspace press in this case.
8988 if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) {
8989 this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
8990 this.blur();
8991 this.focus();
8992 return
8993 }
8994 if (this.composing) { return }
8995 this.rememberSelection();
8996 var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
8997 var head = domToPos(cm, sel.focusNode, sel.focusOffset);
8998 if (anchor && head) { runInOp(cm, function () {
8999 setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
9000 if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
9001 }); }
9002 };
9003
9004 ContentEditableInput.prototype.pollContent = function () {
9005 if (this.readDOMTimeout != null) {
9006 clearTimeout(this.readDOMTimeout);
9007 this.readDOMTimeout = null;
9008 }
9009
9010 var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
9011 var from = sel.from(), to = sel.to();
9012 if (from.ch == 0 && from.line > cm.firstLine())
9013 { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
9014 if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
9015 { to = Pos(to.line + 1, 0); }
9016 if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
9017
9018 var fromIndex, fromLine, fromNode;
9019 if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
9020 fromLine = lineNo(display.view[0].line);
9021 fromNode = display.view[0].node;
9022 } else {
9023 fromLine = lineNo(display.view[fromIndex].line);
9024 fromNode = display.view[fromIndex - 1].node.nextSibling;
9025 }
9026 var toIndex = findViewIndex(cm, to.line);
9027 var toLine, toNode;
9028 if (toIndex == display.view.length - 1) {
9029 toLine = display.viewTo - 1;
9030 toNode = display.lineDiv.lastChild;
9031 } else {
9032 toLine = lineNo(display.view[toIndex + 1].line) - 1;
9033 toNode = display.view[toIndex + 1].node.previousSibling;
9034 }
9035
9036 if (!fromNode) { return false }
9037 var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
9038 var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
9039 while (newText.length > 1 && oldText.length > 1) {
9040 if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
9041 else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
9042 else { break }
9043 }
9044
9045 var cutFront = 0, cutEnd = 0;
9046 var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
9047 while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
9048 { ++cutFront; }
9049 var newBot = lst(newText), oldBot = lst(oldText);
9050 var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
9051 oldBot.length - (oldText.length == 1 ? cutFront : 0));
9052 while (cutEnd < maxCutEnd &&
9053 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
9054 { ++cutEnd; }
9055 // Try to move start of change to start of selection if ambiguous
9056 if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
9057 while (cutFront && cutFront > from.ch &&
9058 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
9059 cutFront--;
9060 cutEnd++;
9061 }
9062 }
9063
9064 newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
9065 newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
9066
9067 var chFrom = Pos(fromLine, cutFront);
9068 var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
9069 if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
9070 replaceRange(cm.doc, newText, chFrom, chTo, "+input");
9071 return true
9072 }
9073 };
9074
9075 ContentEditableInput.prototype.ensurePolled = function () {
9076 this.forceCompositionEnd();
9077 };
9078 ContentEditableInput.prototype.reset = function () {
9079 this.forceCompositionEnd();
9080 };
9081 ContentEditableInput.prototype.forceCompositionEnd = function () {
9082 if (!this.composing) { return }
9083 clearTimeout(this.readDOMTimeout);
9084 this.composing = null;
9085 this.updateFromDOM();
9086 this.div.blur();
9087 this.div.focus();
9088 };
9089 ContentEditableInput.prototype.readFromDOMSoon = function () {
9090 var this$1 = this;
9091
9092 if (this.readDOMTimeout != null) { return }
9093 this.readDOMTimeout = setTimeout(function () {
9094 this$1.readDOMTimeout = null;
9095 if (this$1.composing) {
9096 if (this$1.composing.done) { this$1.composing = null; }
9097 else { return }
9098 }
9099 this$1.updateFromDOM();
9100 }, 80);
9101 };
9102
9103 ContentEditableInput.prototype.updateFromDOM = function () {
9104 var this$1 = this;
9105
9106 if (this.cm.isReadOnly() || !this.pollContent())
9107 { runInOp(this.cm, function () { return regChange(this$1.cm); }); }
9108 };
9109
9110 ContentEditableInput.prototype.setUneditable = function (node) {
9111 node.contentEditable = "false";
9112 };
9113
9114 ContentEditableInput.prototype.onKeyPress = function (e) {
9115 if (e.charCode == 0 || this.composing) { return }
9116 e.preventDefault();
9117 if (!this.cm.isReadOnly())
9118 { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
9119 };
9120
9121 ContentEditableInput.prototype.readOnlyChanged = function (val) {
9122 this.div.contentEditable = String(val != "nocursor");
9123 };
9124
9125 ContentEditableInput.prototype.onContextMenu = function () {};
9126 ContentEditableInput.prototype.resetPosition = function () {};
9127
9128 ContentEditableInput.prototype.needsContentAttribute = true;
9129
9130 function posToDOM(cm, pos) {
9131 var view = findViewForLine(cm, pos.line);
9132 if (!view || view.hidden) { return null }
9133 var line = getLine(cm.doc, pos.line);
9134 var info = mapFromLineView(view, line, pos.line);
9135
9136 var order = getOrder(line, cm.doc.direction), side = "left";
9137 if (order) {
9138 var partPos = getBidiPartAt(order, pos.ch);
9139 side = partPos % 2 ? "right" : "left";
9140 }
9141 var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
9142 result.offset = result.collapse == "right" ? result.end : result.start;
9143 return result
9144 }
9145
9146 function isInGutter(node) {
9147 for (var scan = node; scan; scan = scan.parentNode)
9148 { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
9149 return false
9150 }
9151
9152 function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
9153
9154 function domTextBetween(cm, from, to, fromLine, toLine) {
9155 var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false;
9156 function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
9157 function close() {
9158 if (closing) {
9159 text += lineSep;
9160 if (extraLinebreak) { text += lineSep; }
9161 closing = extraLinebreak = false;
9162 }
9163 }
9164 function addText(str) {
9165 if (str) {
9166 close();
9167 text += str;
9168 }
9169 }
9170 function walk(node) {
9171 if (node.nodeType == 1) {
9172 var cmText = node.getAttribute("cm-text");
9173 if (cmText) {
9174 addText(cmText);
9175 return
9176 }
9177 var markerID = node.getAttribute("cm-marker"), range$$1;
9178 if (markerID) {
9179 var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
9180 if (found.length && (range$$1 = found[0].find(0)))
9181 { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
9182 return
9183 }
9184 if (node.getAttribute("contenteditable") == "false") { return }
9185 var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName);
9186 if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return }
9187
9188 if (isBlock) { close(); }
9189 for (var i = 0; i < node.childNodes.length; i++)
9190 { walk(node.childNodes[i]); }
9191
9192 if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; }
9193 if (isBlock) { closing = true; }
9194 } else if (node.nodeType == 3) {
9195 addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " "));
9196 }
9197 }
9198 for (;;) {
9199 walk(from);
9200 if (from == to) { break }
9201 from = from.nextSibling;
9202 extraLinebreak = false;
9203 }
9204 return text
9205 }
9206
9207 function domToPos(cm, node, offset) {
9208 var lineNode;
9209 if (node == cm.display.lineDiv) {
9210 lineNode = cm.display.lineDiv.childNodes[offset];
9211 if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
9212 node = null; offset = 0;
9213 } else {
9214 for (lineNode = node;; lineNode = lineNode.parentNode) {
9215 if (!lineNode || lineNode == cm.display.lineDiv) { return null }
9216 if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
9217 }
9218 }
9219 for (var i = 0; i < cm.display.view.length; i++) {
9220 var lineView = cm.display.view[i];
9221 if (lineView.node == lineNode)
9222 { return locateNodeInLineView(lineView, node, offset) }
9223 }
9224 }
9225
9226 function locateNodeInLineView(lineView, node, offset) {
9227 var wrapper = lineView.text.firstChild, bad = false;
9228 if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
9229 if (node == wrapper) {
9230 bad = true;
9231 node = wrapper.childNodes[offset];
9232 offset = 0;
9233 if (!node) {
9234 var line = lineView.rest ? lst(lineView.rest) : lineView.line;
9235 return badPos(Pos(lineNo(line), line.text.length), bad)
9236 }
9237 }
9238
9239 var textNode = node.nodeType == 3 ? node : null, topNode = node;
9240 if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
9241 textNode = node.firstChild;
9242 if (offset) { offset = textNode.nodeValue.length; }
9243 }
9244 while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
9245 var measure = lineView.measure, maps = measure.maps;
9246
9247 function find(textNode, topNode, offset) {
9248 for (var i = -1; i < (maps ? maps.length : 0); i++) {
9249 var map$$1 = i < 0 ? measure.map : maps[i];
9250 for (var j = 0; j < map$$1.length; j += 3) {
9251 var curNode = map$$1[j + 2];
9252 if (curNode == textNode || curNode == topNode) {
9253 var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
9254 var ch = map$$1[j] + offset;
9255 if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
9256 return Pos(line, ch)
9257 }
9258 }
9259 }
9260 }
9261 var found = find(textNode, topNode, offset);
9262 if (found) { return badPos(found, bad) }
9263
9264 // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
9265 for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
9266 found = find(after, after.firstChild, 0);
9267 if (found)
9268 { return badPos(Pos(found.line, found.ch - dist), bad) }
9269 else
9270 { dist += after.textContent.length; }
9271 }
9272 for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
9273 found = find(before, before.firstChild, -1);
9274 if (found)
9275 { return badPos(Pos(found.line, found.ch + dist$1), bad) }
9276 else
9277 { dist$1 += before.textContent.length; }
9278 }
9279 }
9280
9281 // TEXTAREA INPUT STYLE
9282
9283 var TextareaInput = function(cm) {
9284 this.cm = cm;
9285 // See input.poll and input.reset
9286 this.prevInput = "";
9287
9288 // Flag that indicates whether we expect input to appear real soon
9289 // now (after some event like 'keypress' or 'input') and are
9290 // polling intensively.
9291 this.pollingFast = false;
9292 // Self-resetting timeout for the poller
9293 this.polling = new Delayed();
9294 // Used to work around IE issue with selection being forgotten when focus moves away from textarea
9295 this.hasSelection = false;
9296 this.composing = null;
9297 };
9298
9299 TextareaInput.prototype.init = function (display) {
9300 var this$1 = this;
9301
9302 var input = this, cm = this.cm;
9303 this.createField(display);
9304 var te = this.textarea;
9305
9306 display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild);
9307
9308 // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
9309 if (ios) { te.style.width = "0px"; }
9310
9311 on(te, "input", function () {
9312 if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
9313 input.poll();
9314 });
9315
9316 on(te, "paste", function (e) {
9317 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
9318
9319 cm.state.pasteIncoming = +new Date;
9320 input.fastPoll();
9321 });
9322
9323 function prepareCopyCut(e) {
9324 if (signalDOMEvent(cm, e)) { return }
9325 if (cm.somethingSelected()) {
9326 setLastCopied({lineWise: false, text: cm.getSelections()});
9327 } else if (!cm.options.lineWiseCopyCut) {
9328 return
9329 } else {
9330 var ranges = copyableRanges(cm);
9331 setLastCopied({lineWise: true, text: ranges.text});
9332 if (e.type == "cut") {
9333 cm.setSelections(ranges.ranges, null, sel_dontScroll);
9334 } else {
9335 input.prevInput = "";
9336 te.value = ranges.text.join("\n");
9337 selectInput(te);
9338 }
9339 }
9340 if (e.type == "cut") { cm.state.cutIncoming = +new Date; }
9341 }
9342 on(te, "cut", prepareCopyCut);
9343 on(te, "copy", prepareCopyCut);
9344
9345 on(display.scroller, "paste", function (e) {
9346 if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
9347 if (!te.dispatchEvent) {
9348 cm.state.pasteIncoming = +new Date;
9349 input.focus();
9350 return
9351 }
9352
9353 // Pass the `paste` event to the textarea so it's handled by its event listener.
9354 var event = new Event("paste");
9355 event.clipboardData = e.clipboardData;
9356 te.dispatchEvent(event);
9357 });
9358
9359 // Prevent normal selection in the editor (we handle our own)
9360 on(display.lineSpace, "selectstart", function (e) {
9361 if (!eventInWidget(display, e)) { e_preventDefault(e); }
9362 });
9363
9364 on(te, "compositionstart", function () {
9365 var start = cm.getCursor("from");
9366 if (input.composing) { input.composing.range.clear(); }
9367 input.composing = {
9368 start: start,
9369 range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
9370 };
9371 });
9372 on(te, "compositionend", function () {
9373 if (input.composing) {
9374 input.poll();
9375 input.composing.range.clear();
9376 input.composing = null;
9377 }
9378 });
9379 };
9380
9381 TextareaInput.prototype.createField = function (_display) {
9382 // Wraps and hides input textarea
9383 this.wrapper = hiddenTextarea();
9384 // The semihidden textarea that is focused when the editor is
9385 // focused, and receives input.
9386 this.textarea = this.wrapper.firstChild;
9387 };
9388
9389 TextareaInput.prototype.prepareSelection = function () {
9390 // Redraw the selection and/or cursor
9391 var cm = this.cm, display = cm.display, doc = cm.doc;
9392 var result = prepareSelection(cm);
9393
9394 // Move the hidden textarea near the cursor to prevent scrolling artifacts
9395 if (cm.options.moveInputWithCursor) {
9396 var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
9397 var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
9398 result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
9399 headPos.top + lineOff.top - wrapOff.top));
9400 result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
9401 headPos.left + lineOff.left - wrapOff.left));
9402 }
9403
9404 return result
9405 };
9406
9407 TextareaInput.prototype.showSelection = function (drawn) {
9408 var cm = this.cm, display = cm.display;
9409 removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
9410 removeChildrenAndAdd(display.selectionDiv, drawn.selection);
9411 if (drawn.teTop != null) {
9412 this.wrapper.style.top = drawn.teTop + "px";
9413 this.wrapper.style.left = drawn.teLeft + "px";
9414 }
9415 };
9416
9417 // Reset the input to correspond to the selection (or to be empty,
9418 // when not typing and nothing is selected)
9419 TextareaInput.prototype.reset = function (typing) {
9420 if (this.contextMenuPending || this.composing) { return }
9421 var cm = this.cm;
9422 if (cm.somethingSelected()) {
9423 this.prevInput = "";
9424 var content = cm.getSelection();
9425 this.textarea.value = content;
9426 if (cm.state.focused) { selectInput(this.textarea); }
9427 if (ie && ie_version >= 9) { this.hasSelection = content; }
9428 } else if (!typing) {
9429 this.prevInput = this.textarea.value = "";
9430 if (ie && ie_version >= 9) { this.hasSelection = null; }
9431 }
9432 };
9433
9434 TextareaInput.prototype.getField = function () { return this.textarea };
9435
9436 TextareaInput.prototype.supportsTouch = function () { return false };
9437
9438 TextareaInput.prototype.focus = function () {
9439 if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
9440 try { this.textarea.focus(); }
9441 catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
9442 }
9443 };
9444
9445 TextareaInput.prototype.blur = function () { this.textarea.blur(); };
9446
9447 TextareaInput.prototype.resetPosition = function () {
9448 this.wrapper.style.top = this.wrapper.style.left = 0;
9449 };
9450
9451 TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
9452
9453 // Poll for input changes, using the normal rate of polling. This
9454 // runs as long as the editor is focused.
9455 TextareaInput.prototype.slowPoll = function () {
9456 var this$1 = this;
9457
9458 if (this.pollingFast) { return }
9459 this.polling.set(this.cm.options.pollInterval, function () {
9460 this$1.poll();
9461 if (this$1.cm.state.focused) { this$1.slowPoll(); }
9462 });
9463 };
9464
9465 // When an event has just come in that is likely to add or change
9466 // something in the input textarea, we poll faster, to ensure that
9467 // the change appears on the screen quickly.
9468 TextareaInput.prototype.fastPoll = function () {
9469 var missed = false, input = this;
9470 input.pollingFast = true;
9471 function p() {
9472 var changed = input.poll();
9473 if (!changed && !missed) {missed = true; input.polling.set(60, p);}
9474 else {input.pollingFast = false; input.slowPoll();}
9475 }
9476 input.polling.set(20, p);
9477 };
9478
9479 // Read input from the textarea, and update the document to match.
9480 // When something is selected, it is present in the textarea, and
9481 // selected (unless it is huge, in which case a placeholder is
9482 // used). When nothing is selected, the cursor sits after previously
9483 // seen text (can be empty), which is stored in prevInput (we must
9484 // not reset the textarea when typing, because that breaks IME).
9485 TextareaInput.prototype.poll = function () {
9486 var this$1 = this;
9487
9488 var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
9489 // Since this is called a *lot*, try to bail out as cheaply as
9490 // possible when it is clear that nothing happened. hasSelection
9491 // will be the case when there is a lot of text in the textarea,
9492 // in which case reading its value would be expensive.
9493 if (this.contextMenuPending || !cm.state.focused ||
9494 (hasSelection(input) && !prevInput && !this.composing) ||
9495 cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
9496 { return false }
9497
9498 var text = input.value;
9499 // If nothing changed, bail.
9500 if (text == prevInput && !cm.somethingSelected()) { return false }
9501 // Work around nonsensical selection resetting in IE9/10, and
9502 // inexplicable appearance of private area unicode characters on
9503 // some key combos in Mac (#2689).
9504 if (ie && ie_version >= 9 && this.hasSelection === text ||
9505 mac && /[\uf700-\uf7ff]/.test(text)) {
9506 cm.display.input.reset();
9507 return false
9508 }
9509
9510 if (cm.doc.sel == cm.display.selForContextMenu) {
9511 var first = text.charCodeAt(0);
9512 if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
9513 if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
9514 }
9515 // Find the part of the input that is actually new
9516 var same = 0, l = Math.min(prevInput.length, text.length);
9517 while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
9518
9519 runInOp(cm, function () {
9520 applyTextInput(cm, text.slice(same), prevInput.length - same,
9521 null, this$1.composing ? "*compose" : null);
9522
9523 // Don't leave long text in the textarea, since it makes further polling slow
9524 if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
9525 else { this$1.prevInput = text; }
9526
9527 if (this$1.composing) {
9528 this$1.composing.range.clear();
9529 this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
9530 {className: "CodeMirror-composing"});
9531 }
9532 });
9533 return true
9534 };
9535
9536 TextareaInput.prototype.ensurePolled = function () {
9537 if (this.pollingFast && this.poll()) { this.pollingFast = false; }
9538 };
9539
9540 TextareaInput.prototype.onKeyPress = function () {
9541 if (ie && ie_version >= 9) { this.hasSelection = null; }
9542 this.fastPoll();
9543 };
9544
9545 TextareaInput.prototype.onContextMenu = function (e) {
9546 var input = this, cm = input.cm, display = cm.display, te = input.textarea;
9547 if (input.contextMenuPending) { input.contextMenuPending(); }
9548 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
9549 if (!pos || presto) { return } // Opera is difficult.
9550
9551 // Reset the current text selection only if the click is done outside of the selection
9552 // and 'resetSelectionOnContextMenu' option is true.
9553 var reset = cm.options.resetSelectionOnContextMenu;
9554 if (reset && cm.doc.sel.contains(pos) == -1)
9555 { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
9556
9557 var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
9558 var wrapperBox = input.wrapper.offsetParent.getBoundingClientRect();
9559 input.wrapper.style.cssText = "position: static";
9560 te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
9561 var oldScrollY;
9562 if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
9563 display.input.focus();
9564 if (webkit) { window.scrollTo(null, oldScrollY); }
9565 display.input.reset();
9566 // Adds "Select all" to context menu in FF
9567 if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
9568 input.contextMenuPending = rehide;
9569 display.selForContextMenu = cm.doc.sel;
9570 clearTimeout(display.detectingSelectAll);
9571
9572 // Select-all will be greyed out if there's nothing to select, so
9573 // this adds a zero-width space so that we can later check whether
9574 // it got selected.
9575 function prepareSelectAllHack() {
9576 if (te.selectionStart != null) {
9577 var selected = cm.somethingSelected();
9578 var extval = "\u200b" + (selected ? te.value : "");
9579 te.value = "\u21da"; // Used to catch context-menu undo
9580 te.value = extval;
9581 input.prevInput = selected ? "" : "\u200b";
9582 te.selectionStart = 1; te.selectionEnd = extval.length;
9583 // Re-set this, in case some other handler touched the
9584 // selection in the meantime.
9585 display.selForContextMenu = cm.doc.sel;
9586 }
9587 }
9588 function rehide() {
9589 if (input.contextMenuPending != rehide) { return }
9590 input.contextMenuPending = false;
9591 input.wrapper.style.cssText = oldWrapperCSS;
9592 te.style.cssText = oldCSS;
9593 if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
9594
9595 // Try to detect the user choosing select-all
9596 if (te.selectionStart != null) {
9597 if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
9598 var i = 0, poll = function () {
9599 if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
9600 te.selectionEnd > 0 && input.prevInput == "\u200b") {
9601 operation(cm, selectAll)(cm);
9602 } else if (i++ < 10) {
9603 display.detectingSelectAll = setTimeout(poll, 500);
9604 } else {
9605 display.selForContextMenu = null;
9606 display.input.reset();
9607 }
9608 };
9609 display.detectingSelectAll = setTimeout(poll, 200);
9610 }
9611 }
9612
9613 if (ie && ie_version >= 9) { prepareSelectAllHack(); }
9614 if (captureRightClick) {
9615 e_stop(e);
9616 var mouseup = function () {
9617 off(window, "mouseup", mouseup);
9618 setTimeout(rehide, 20);
9619 };
9620 on(window, "mouseup", mouseup);
9621 } else {
9622 setTimeout(rehide, 50);
9623 }
9624 };
9625
9626 TextareaInput.prototype.readOnlyChanged = function (val) {
9627 if (!val) { this.reset(); }
9628 this.textarea.disabled = val == "nocursor";
9629 };
9630
9631 TextareaInput.prototype.setUneditable = function () {};
9632
9633 TextareaInput.prototype.needsContentAttribute = false;
9634
9635 function fromTextArea(textarea, options) {
9636 options = options ? copyObj(options) : {};
9637 options.value = textarea.value;
9638 if (!options.tabindex && textarea.tabIndex)
9639 { options.tabindex = textarea.tabIndex; }
9640 if (!options.placeholder && textarea.placeholder)
9641 { options.placeholder = textarea.placeholder; }
9642 // Set autofocus to true if this textarea is focused, or if it has
9643 // autofocus and no other element is focused.
9644 if (options.autofocus == null) {
9645 var hasFocus = activeElt();
9646 options.autofocus = hasFocus == textarea ||
9647 textarea.getAttribute("autofocus") != null && hasFocus == document.body;
9648 }
9649
9650 function save() {textarea.value = cm.getValue();}
9651
9652 var realSubmit;
9653 if (textarea.form) {
9654 on(textarea.form, "submit", save);
9655 // Deplorable hack to make the submit method do the right thing.
9656 if (!options.leaveSubmitMethodAlone) {
9657 var form = textarea.form;
9658 realSubmit = form.submit;
9659 try {
9660 var wrappedSubmit = form.submit = function () {
9661 save();
9662 form.submit = realSubmit;
9663 form.submit();
9664 form.submit = wrappedSubmit;
9665 };
9666 } catch(e) {}
9667 }
9668 }
9669
9670 options.finishInit = function (cm) {
9671 cm.save = save;
9672 cm.getTextArea = function () { return textarea; };
9673 cm.toTextArea = function () {
9674 cm.toTextArea = isNaN; // Prevent this from being ran twice
9675 save();
9676 textarea.parentNode.removeChild(cm.getWrapperElement());
9677 textarea.style.display = "";
9678 if (textarea.form) {
9679 off(textarea.form, "submit", save);
9680 if (!options.leaveSubmitMethodAlone && typeof textarea.form.submit == "function")
9681 { textarea.form.submit = realSubmit; }
9682 }
9683 };
9684 };
9685
9686 textarea.style.display = "none";
9687 var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
9688 options);
9689 return cm
9690 }
9691
9692 function addLegacyProps(CodeMirror) {
9693 CodeMirror.off = off;
9694 CodeMirror.on = on;
9695 CodeMirror.wheelEventPixels = wheelEventPixels;
9696 CodeMirror.Doc = Doc;
9697 CodeMirror.splitLines = splitLinesAuto;
9698 CodeMirror.countColumn = countColumn;
9699 CodeMirror.findColumn = findColumn;
9700 CodeMirror.isWordChar = isWordCharBasic;
9701 CodeMirror.Pass = Pass;
9702 CodeMirror.signal = signal;
9703 CodeMirror.Line = Line;
9704 CodeMirror.changeEnd = changeEnd;
9705 CodeMirror.scrollbarModel = scrollbarModel;
9706 CodeMirror.Pos = Pos;
9707 CodeMirror.cmpPos = cmp;
9708 CodeMirror.modes = modes;
9709 CodeMirror.mimeModes = mimeModes;
9710 CodeMirror.resolveMode = resolveMode;
9711 CodeMirror.getMode = getMode;
9712 CodeMirror.modeExtensions = modeExtensions;
9713 CodeMirror.extendMode = extendMode;
9714 CodeMirror.copyState = copyState;
9715 CodeMirror.startState = startState;
9716 CodeMirror.innerMode = innerMode;
9717 CodeMirror.commands = commands;
9718 CodeMirror.keyMap = keyMap;
9719 CodeMirror.keyName = keyName;
9720 CodeMirror.isModifierKey = isModifierKey;
9721 CodeMirror.lookupKey = lookupKey;
9722 CodeMirror.normalizeKeyMap = normalizeKeyMap;
9723 CodeMirror.StringStream = StringStream;
9724 CodeMirror.SharedTextMarker = SharedTextMarker;
9725 CodeMirror.TextMarker = TextMarker;
9726 CodeMirror.LineWidget = LineWidget;
9727 CodeMirror.e_preventDefault = e_preventDefault;
9728 CodeMirror.e_stopPropagation = e_stopPropagation;
9729 CodeMirror.e_stop = e_stop;
9730 CodeMirror.addClass = addClass;
9731 CodeMirror.contains = contains;
9732 CodeMirror.rmClass = rmClass;
9733 CodeMirror.keyNames = keyNames;
9734 }
9735
9736 // EDITOR CONSTRUCTOR
9737
9738 defineOptions(CodeMirror);
9739
9740 addEditorMethods(CodeMirror);
9741
9742 // Set up methods on CodeMirror's prototype to redirect to the editor's document.
9743 var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
9744 for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
9745 { CodeMirror.prototype[prop] = (function(method) {
9746 return function() {return method.apply(this.doc, arguments)}
9747 })(Doc.prototype[prop]); } }
9748
9749 eventMixin(Doc);
9750 CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
9751
9752 // Extra arguments are stored as the mode's dependencies, which is
9753 // used by (legacy) mechanisms like loadmode.js to automatically
9754 // load a mode. (Preferred mechanism is the require/define calls.)
9755 CodeMirror.defineMode = function(name/*, mode, …*/) {
9756 if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name; }
9757 defineMode.apply(this, arguments);
9758 };
9759
9760 CodeMirror.defineMIME = defineMIME;
9761
9762 // Minimal default mode.
9763 CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
9764 CodeMirror.defineMIME("text/plain", "null");
9765
9766 // EXTENSIONS
9767
9768 CodeMirror.defineExtension = function (name, func) {
9769 CodeMirror.prototype[name] = func;
9770 };
9771 CodeMirror.defineDocExtension = function (name, func) {
9772 Doc.prototype[name] = func;
9773 };
9774
9775 CodeMirror.fromTextArea = fromTextArea;
9776
9777 addLegacyProps(CodeMirror);
9778
9779 CodeMirror.version = "5.49.2";
8888
9780
8889 return CodeMirror;
9781 return CodeMirror;
8890 });
9782
9783 })));
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -46,6 +46,10 b''
46 completion.update(true);
46 completion.update(true);
47 });
47 });
48
48
49 CodeMirror.defineExtension("closeHint", function() {
50 if (this.state.completionActive) this.state.completionActive.close()
51 })
52
49 function Completion(cm, options) {
53 function Completion(cm, options) {
50 this.cm = cm;
54 this.cm = cm;
51 this.options = options;
55 this.options = options;
@@ -98,7 +102,7 b''
98 var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
102 var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
99 if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
103 if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
100 pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
104 pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
101 (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
105 (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
102 this.close();
106 this.close();
103 } else {
107 } else {
104 var self = this;
108 var self = this;
@@ -108,24 +112,21 b''
108 },
112 },
109
113
110 update: function(first) {
114 update: function(first) {
111 if (this.tick == null) return;
115 if (this.tick == null) return
112 if (!this.options.hint.async) {
116 var self = this, myTick = ++this.tick
113 this.finishUpdate(this.options.hint(this.cm, this.options), first);
117 fetchHints(this.options.hint, this.cm, this.options, function(data) {
114 } else {
118 if (self.tick == myTick) self.finishUpdate(data, first)
115 var myTick = ++this.tick, self = this;
119 })
116 this.options.hint(this.cm, function(data) {
117 if (self.tick == myTick) self.finishUpdate(data, first);
118 }, this.options);
119 }
120 },
120 },
121
121
122 finishUpdate: function(data, first) {
122 finishUpdate: function(data, first) {
123 if (this.data) CodeMirror.signal(this.data, "update");
123 if (this.data) CodeMirror.signal(this.data, "update");
124 if (data && this.data && CodeMirror.cmpPos(data.from, this.data.from)) data = null;
125 this.data = data;
126
124
127 var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
125 var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
128 if (this.widget) this.widget.close();
126 if (this.widget) this.widget.close();
127
128 this.data = data;
129
129 if (data && data.list.length) {
130 if (data && data.list.length) {
130 if (picked && data.list.length == 1) {
131 if (picked && data.list.length == 1) {
131 this.pick(data, 0);
132 this.pick(data, 0);
@@ -166,6 +167,14 b''
166 Tab: handle.pick,
167 Tab: handle.pick,
167 Esc: handle.close
168 Esc: handle.close
168 };
169 };
170
171 var mac = /Mac/.test(navigator.platform);
172
173 if (mac) {
174 baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);};
175 baseMap["Ctrl-N"] = function() {handle.moveFocus(1);};
176 }
177
169 var custom = completion.options.customKeys;
178 var custom = completion.options.customKeys;
170 var ourMap = custom ? {} : baseMap;
179 var ourMap = custom ? {} : baseMap;
171 function addBinding(key, val) {
180 function addBinding(key, val) {
@@ -201,43 +210,61 b''
201 this.data = data;
210 this.data = data;
202 this.picked = false;
211 this.picked = false;
203 var widget = this, cm = completion.cm;
212 var widget = this, cm = completion.cm;
213 var ownerDocument = cm.getInputField().ownerDocument;
214 var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow;
204
215
205 var hints = this.hints = document.createElement("ul");
216 var hints = this.hints = ownerDocument.createElement("ul");
206 hints.className = "CodeMirror-hints";
217 var theme = completion.cm.options.theme;
218 hints.className = "CodeMirror-hints " + theme;
207 this.selectedHint = data.selectedHint || 0;
219 this.selectedHint = data.selectedHint || 0;
208
220
209 var completions = data.list;
221 var completions = data.list;
210 for (var i = 0; i < completions.length; ++i) {
222 for (var i = 0; i < completions.length; ++i) {
211 var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
223 var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i];
212 var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
224 var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
213 if (cur.className != null) className = cur.className + " " + className;
225 if (cur.className != null) className = cur.className + " " + className;
214 elt.className = className;
226 elt.className = className;
215 if (cur.render) cur.render(elt, data, cur);
227 if (cur.render) cur.render(elt, data, cur);
216 else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
228 else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur)));
217 elt.hintId = i;
229 elt.hintId = i;
218 }
230 }
219
231
232 var container = completion.options.container || ownerDocument.body;
220 var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
233 var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
221 var left = pos.left, top = pos.bottom, below = true;
234 var left = pos.left, top = pos.bottom, below = true;
222 hints.style.left = left + "px";
235 var offsetLeft = 0, offsetTop = 0;
223 hints.style.top = top + "px";
236 if (container !== ownerDocument.body) {
237 // We offset the cursor position because left and top are relative to the offsetParent's top left corner.
238 var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1;
239 var offsetParent = isContainerPositioned ? container : container.offsetParent;
240 var offsetParentPosition = offsetParent.getBoundingClientRect();
241 var bodyPosition = ownerDocument.body.getBoundingClientRect();
242 offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft);
243 offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop);
244 }
245 hints.style.left = (left - offsetLeft) + "px";
246 hints.style.top = (top - offsetTop) + "px";
247
224 // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
248 // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
225 var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
249 var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth);
226 var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
250 var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight);
227 (completion.options.container || document.body).appendChild(hints);
251 container.appendChild(hints);
228 var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
252 var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
253 var scrolls = hints.scrollHeight > hints.clientHeight + 1
254 var startScroll = cm.getScrollInfo();
255
229 if (overlapY > 0) {
256 if (overlapY > 0) {
230 var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
257 var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
231 if (curTop - height > 0) { // Fits above cursor
258 if (curTop - height > 0) { // Fits above cursor
232 hints.style.top = (top = pos.top - height) + "px";
259 hints.style.top = (top = pos.top - height - offsetTop) + "px";
233 below = false;
260 below = false;
234 } else if (height > winH) {
261 } else if (height > winH) {
235 hints.style.height = (winH - 5) + "px";
262 hints.style.height = (winH - 5) + "px";
236 hints.style.top = (top = pos.bottom - box.top) + "px";
263 hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px";
237 var cursor = cm.getCursor();
264 var cursor = cm.getCursor();
238 if (data.from.ch != cursor.ch) {
265 if (data.from.ch != cursor.ch) {
239 pos = cm.cursorCoords(cursor);
266 pos = cm.cursorCoords(cursor);
240 hints.style.left = (left = pos.left) + "px";
267 hints.style.left = (left = pos.left - offsetLeft) + "px";
241 box = hints.getBoundingClientRect();
268 box = hints.getBoundingClientRect();
242 }
269 }
243 }
270 }
@@ -248,8 +275,10 b''
248 hints.style.width = (winW - 5) + "px";
275 hints.style.width = (winW - 5) + "px";
249 overlapX -= (box.right - box.left) - winW;
276 overlapX -= (box.right - box.left) - winW;
250 }
277 }
251 hints.style.left = (left = pos.left - overlapX) + "px";
278 hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px";
252 }
279 }
280 if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
281 node.style.paddingRight = cm.display.nativeBarWidth + "px"
253
282
254 cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
283 cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
255 moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
284 moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
@@ -267,11 +296,10 b''
267 cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
296 cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
268 }
297 }
269
298
270 var startScroll = cm.getScrollInfo();
271 cm.on("scroll", this.onScroll = function() {
299 cm.on("scroll", this.onScroll = function() {
272 var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
300 var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
273 var newTop = top + startScroll.top - curScroll.top;
301 var newTop = top + startScroll.top - curScroll.top;
274 var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
302 var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop);
275 if (!below) point += hints.offsetHeight;
303 if (!below) point += hints.offsetHeight;
276 if (point <= editor.top || point >= editor.bottom) return completion.close();
304 if (point <= editor.top || point >= editor.bottom) return completion.close();
277 hints.style.top = newTop + "px";
305 hints.style.top = newTop + "px";
@@ -295,7 +323,7 b''
295 setTimeout(function(){cm.focus();}, 20);
323 setTimeout(function(){cm.focus();}, 20);
296 });
324 });
297
325
298 CodeMirror.signal(data, "select", completions[0], hints.firstChild);
326 CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
299 return true;
327 return true;
300 }
328 }
301
329
@@ -332,7 +360,7 b''
332 i = avoidWrap ? 0 : this.data.list.length - 1;
360 i = avoidWrap ? 0 : this.data.list.length - 1;
333 if (this.selectedHint == i) return;
361 if (this.selectedHint == i) return;
334 var node = this.hints.childNodes[this.selectedHint];
362 var node = this.hints.childNodes[this.selectedHint];
335 node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
363 if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
336 node = this.hints.childNodes[this.selectedHint = i];
364 node = this.hints.childNodes[this.selectedHint = i];
337 node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
365 node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
338 if (node.offsetTop < this.hints.scrollTop)
366 if (node.offsetTop < this.hints.scrollTop)
@@ -355,40 +383,31 b''
355 return result
383 return result
356 }
384 }
357
385
386 function fetchHints(hint, cm, options, callback) {
387 if (hint.async) {
388 hint(cm, callback, options)
389 } else {
390 var result = hint(cm, options)
391 if (result && result.then) result.then(callback)
392 else callback(result)
393 }
394 }
395
358 function resolveAutoHints(cm, pos) {
396 function resolveAutoHints(cm, pos) {
359 var helpers = cm.getHelpers(pos, "hint"), words
397 var helpers = cm.getHelpers(pos, "hint"), words
360 if (helpers.length) {
398 if (helpers.length) {
361 var async = false, resolved
399 var resolved = function(cm, callback, options) {
362 for (var i = 0; i < helpers.length; i++) if (helpers[i].async) async = true
400 var app = applicableHelpers(cm, helpers);
363 if (async) {
401 function run(i) {
364 resolved = function(cm, callback, options) {
365 var app = applicableHelpers(cm, helpers)
366 function run(i, result) {
367 if (i == app.length) return callback(null)
402 if (i == app.length) return callback(null)
368 var helper = app[i]
403 fetchHints(app[i], cm, options, function(result) {
369 if (helper.async) {
404 if (result && result.list.length > 0) callback(result)
370 helper(cm, function(result) {
371 if (result) callback(result)
372 else run(i + 1)
405 else run(i + 1)
373 }, options)
406 })
374 } else {
375 var result = helper(cm, options)
376 if (result) callback(result)
377 else run(i + 1)
378 }
379 }
407 }
380 run(0)
408 run(0)
381 }
409 }
382 resolved.async = true
410 resolved.async = true
383 } else {
384 resolved = function(cm, options) {
385 var app = applicableHelpers(cm, helpers)
386 for (var i = 0; i < app.length; i++) {
387 var cur = app[i](cm, options)
388 if (cur && cur.list.length) return cur
389 }
390 }
391 }
392 resolved.supportsSelection = true
411 resolved.supportsSelection = true
393 return resolved
412 return resolved
394 } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
413 } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
@@ -405,12 +424,13 b''
405 });
424 });
406
425
407 CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
426 CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
408 var cur = cm.getCursor(), token = cm.getTokenAt(cur);
427 var cur = cm.getCursor(), token = cm.getTokenAt(cur)
409 var to = CodeMirror.Pos(cur.line, token.end);
428 var term, from = CodeMirror.Pos(cur.line, token.start), to = cur
410 if (token.string && /\w/.test(token.string[token.string.length - 1])) {
429 if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) {
411 var term = token.string, from = CodeMirror.Pos(cur.line, token.start);
430 term = token.string.substr(0, cur.ch - token.start)
412 } else {
431 } else {
413 var term = "", from = to;
432 term = ""
433 from = cur
414 }
434 }
415 var found = [];
435 var found = [];
416 for (var i = 0; i < options.words.length; i++) {
436 for (var i = 0; i < options.words.length; i++) {
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 // Utility function that allows modes to be combined. The mode given
4 // Utility function that allows modes to be combined. The mode given
5 // as the base argument takes care of most of the normal mode
5 // as the base argument takes care of most of the normal mode
@@ -68,16 +68,21 b' CodeMirror.overlayMode = function(base, '
68 else return state.overlayCur;
68 else return state.overlayCur;
69 },
69 },
70
70
71 indent: base.indent && function(state, textAfter) {
71 indent: base.indent && function(state, textAfter, line) {
72 return base.indent(state.base, textAfter);
72 return base.indent(state.base, textAfter, line);
73 },
73 },
74 electricChars: base.electricChars,
74 electricChars: base.electricChars,
75
75
76 innerMode: function(state) { return {state: state.base, mode: base}; },
76 innerMode: function(state) { return {state: state.base, mode: base}; },
77
77
78 blankLine: function(state) {
78 blankLine: function(state) {
79 if (base.blankLine) base.blankLine(state.base);
79 var baseToken, overlayToken;
80 if (overlay.blankLine) overlay.blankLine(state.overlay);
80 if (base.blankLine) baseToken = base.blankLine(state.base);
81 if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay);
82
83 return overlayToken == null ?
84 baseToken :
85 (combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken);
81 }
86 }
82 };
87 };
83 };
88 };
@@ -1,5 +1,5 b''
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
3
3
4 (function(mod) {
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
@@ -14,10 +14,12 b''
14 if (val && !prev) {
14 if (val && !prev) {
15 cm.on("blur", onBlur);
15 cm.on("blur", onBlur);
16 cm.on("change", onChange);
16 cm.on("change", onChange);
17 cm.on("swapDoc", onChange);
17 onChange(cm);
18 onChange(cm);
18 } else if (!val && prev) {
19 } else if (!val && prev) {
19 cm.off("blur", onBlur);
20 cm.off("blur", onBlur);
20 cm.off("change", onChange);
21 cm.off("change", onChange);
22 cm.off("swapDoc", onChange);
21 clearPlaceholder(cm);
23 clearPlaceholder(cm);
22 var wrapper = cm.getWrapperElement();
24 var wrapper = cm.getWrapperElement();
23 wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
25 wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
@@ -36,7 +38,8 b''
36 clearPlaceholder(cm);
38 clearPlaceholder(cm);
37 var elt = cm.state.placeholder = document.createElement("pre");
39 var elt = cm.state.placeholder = document.createElement("pre");
38 elt.style.cssText = "height: 0; overflow: visible";
40 elt.style.cssText = "height: 0; overflow: visible";
39 elt.className = "CodeMirror-placeholder";
41 elt.style.direction = cm.getOption("direction");
42 elt.className = "CodeMirror-placeholder CodeMirror-line-like";
40 var placeHolder = cm.getOption("placeholder")
43 var placeHolder = cm.getOption("placeholder")
41 if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
44 if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
42 elt.appendChild(placeHolder)
45 elt.appendChild(placeHolder)
General Comments 0
You need to be logged in to leave comments. Login now