1// CodeMirror, copyright (c) by Marijn Haverbeke and others 2// Distributed under an MIT license: http://codemirror.net/LICENSE 3 4(function(mod) { 5 if (typeof exports == "object" && typeof module == "object") // CommonJS 6 mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta")); 7 else if (typeof define == "function" && define.amd) // AMD 8 define(["../../lib/codemirror", "../xml/xml", "../meta"], mod); 9 else // Plain browser env 10 mod(CodeMirror); 11})(function(CodeMirror) { 12"use strict"; 13 14CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { 15 16 var htmlMode = CodeMirror.getMode(cmCfg, "text/html"); 17 var htmlModeMissing = htmlMode.name == "null" 18 19 function getMode(name) { 20 if (CodeMirror.findModeByName) { 21 var found = CodeMirror.findModeByName(name); 22 if (found) name = found.mime || found.mimes[0]; 23 } 24 var mode = CodeMirror.getMode(cmCfg, name); 25 return mode.name == "null" ? null : mode; 26 } 27 28 // Should characters that affect highlighting be highlighted separate? 29 // Does not include characters that will be output (such as `1.` and `-` for lists) 30 if (modeCfg.highlightFormatting === undefined) 31 modeCfg.highlightFormatting = false; 32 33 // Maximum number of nested blockquotes. Set to 0 for infinite nesting. 34 // Excess `>` will emit `error` token. 35 if (modeCfg.maxBlockquoteDepth === undefined) 36 modeCfg.maxBlockquoteDepth = 0; 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] ") 48 if (modeCfg.taskLists === undefined) modeCfg.taskLists = false; 49 50 // Turn on strikethrough syntax 51 if (modeCfg.strikethrough === undefined) 52 modeCfg.strikethrough = false; 53 54 // Allow token types to be overridden by user-provided token types. 55 if (modeCfg.tokenTypeOverrides === undefined) 56 modeCfg.tokenTypeOverrides = {}; 57 58 var tokenTypes = { 59 header: "header", 60 code: "comment", 61 quote: "quote", 62 list1: "variable-2", 63 list2: "variable-3", 64 list3: "keyword", 65 hr: "hr", 66 image: "image", 67 imageAltText: "image-alt-text", 68 imageMarker: "image-marker", 69 formatting: "formatting", 70 linkInline: "link", 71 linkEmail: "link", 72 linkText: "link", 73 linkHref: "string", 74 em: "em", 75 strong: "strong", 76 strikethrough: "strikethrough" 77 }; 78 79 for (var tokenType in tokenTypes) { 80 if (tokenTypes.hasOwnProperty(tokenType) && modeCfg.tokenTypeOverrides[tokenType]) { 81 tokenTypes[tokenType] = modeCfg.tokenTypeOverrides[tokenType]; 82 } 83 } 84 85 var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/ 86 , ulRE = /^[*\-+]\s+/ 87 , olRE = /^[0-9]+([.)])\s+/ 88 , taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE 89 , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/ 90 , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/ 91 , textRE = /^[^#!\[\]*_\\<>` "'(~]+/ 92 , fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) + 93 ")[ \\t]*([\\w+#\-]*)"); 94 95 function switchInline(stream, state, f) { 96 state.f = state.inline = f; 97 return f(stream, state); 98 } 99 100 function switchBlock(stream, state, f) { 101 state.f = state.block = f; 102 return f(stream, state); 103 } 104 105 function lineIsEmpty(line) { 106 return !line || !/\S/.test(line.string) 107 } 108 109 // Blocks 110 111 function blankLine(state) { 112 // Reset linkTitle state 113 state.linkTitle = false; 114 // Reset EM state 115 state.em = false; 116 // Reset STRONG state 117 state.strong = false; 118 // Reset strikethrough state 119 state.strikethrough = false; 120 // Reset state.quote 121 state.quote = 0; 122 // Reset state.indentedCode 123 state.indentedCode = false; 124 if (htmlModeMissing && state.f == htmlBlock) { 125 state.f = inlineNormal; 126 state.block = blockNormal; 127 } 128 // Reset state.trailingSpace 129 state.trailingSpace = 0; 130 state.trailingSpaceNewLine = false;
131 // Mark this line as blank 132 state.prevLine = state.thisLine 133 state.thisLine = null 134 return null; 135 } 136 137 function blockNormal(stream, state) { 138 139 var sol = stream.sol(); 140 141 var prevLineIsList = state.list !== false, 142 prevLineIsIndentedCode = state.indentedCode; 143 144 state.indentedCode = false; 145 146 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; 152 } else if (state.indentation > 0) { 153 state.list = null; 154 } else { // No longer a list 155 state.list = false; 156 } 157 } 158 159 var match = null; 160 if (state.indentationDiff >= 4) { 161 stream.skipToEnd(); 162 if (prevLineIsIndentedCode || lineIsEmpty(state.prevLine)) { 163 state.indentation -= 4; 164 state.indentedCode = true; 165 return tokenTypes.code; 166 } else { 167 return null; 168 } 169 } else if (stream.eatSpace()) { 170 return null; 171 } else if ((match = stream.match(atxHeaderRE)) && match[1].length <= 6) { 172 state.header = match[1].length; 173 if (modeCfg.highlightFormatting) state.formatting = "header"; 174 state.f = state.inline; 175 return getType(state); 176 } else if (!lineIsEmpty(state.prevLine) && !state.quote && !prevLineIsList && 177 !prevLineIsIndentedCode && (match = stream.match(setextHeaderRE))) { 178 state.header = match[0].charAt(0) == '=' ? 1 : 2; 179 if (modeCfg.highlightFormatting) state.formatting = "header"; 180 state.f = state.inline; 181 return getType(state); 182 } else if (stream.eat('>')) { 183 state.quote = sol ? 1 : state.quote + 1; 184 if (modeCfg.highlightFormatting) state.formatting = "quote"; 185 stream.eatSpace(); 186 return getType(state); 187 } else if (stream.peek() === '[') { 188 return switchInline(stream, state, footnoteLink); 189 } else if (stream.match(hrRE, true)) { 190 state.hr = true; 191 return tokenTypes.hr; 192 } else if ((lineIsEmpty(state.prevLine) || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) { 193 var listType = null; 194 if (stream.match(ulRE, true)) { 195 listType = 'ul'; 196 } else { 197 stream.match(olRE, true); 198 listType = 'ol'; 199 } 200 state.indentation = stream.column() + stream.current().length; 201 state.list = true; 202 203 // While this list item's marker's indentation 204 // is less than the deepest list item's content's indentation, 205 // pop the deepest list item indentation off the stack. 206 while (state.listStack && stream.column() < state.listStack[state.listStack.length - 1]) { 207 state.listStack.pop(); 208 } 209 210 // Add this list item's content's indentation to the stack 211 state.listStack.push(state.indentation); 212 213 if (modeCfg.taskLists && stream.match(taskListRE, false)) { 214 state.taskList = true; 215 } 216 state.f = state.inline; 217 if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType]; 218 return getType(state); 219 } else if (modeCfg.fencedCodeBlocks && (match = stream.match(fencedCodeRE, true))) { 220 state.fencedChars = match[1] 221 // try switching mode 222 state.localMode = getMode(match[2]); 223 if (state.localMode) state.localState = CodeMirror.startState(state.localMode); 224 state.f = state.block = local; 225 if (modeCfg.highlightFormatting) state.formatting = "code-block"; 226 state.code = -1 227 return getType(state); 228 } 229 230 return switchInline(stream, state, state.inline); 231 } 232 233 function htmlBlock(stream, state) { 234 var style = htmlMode.token(stream, state.htmlState); 235 if (!htmlModeMissing) { 236 var inner = CodeMirror.innerMode(htmlMode, state.htmlState) 237 if ((inner.mode.name == "xml" && inner.state.tagStart === null && 238 (!inner.state.context && inner.state.tokenize.isInText)) || 239 (state.md_inside && stream.current().indexOf(">") > -1)) { 240 state.f = inlineNormal; 241 state.block = blockNormal; 242 state.htmlState = null; 243 } 244 } 245 return style; 246 } 247 248 function local(stream, state) { 249 if (state.fencedChars && stream.match(state.fencedChars, false)) { 250 state.localMode = state.localState = null; 251 state.f = state.block = leavingLocal; 252 return null; 253 } else if (state.localMode) { 254 return state.localMode.token(stream, state.localState); 255 } else { 256 stream.skipToEnd(); 257 return tokenTypes.code; 258 } 259 } 260 261 function leavingLocal(stream, state) { 262 stream.match(state.fencedChars); 263 state.block = blockNormal; 264 state.f = inlineNormal; 265 state.fencedChars = null; 266 if (modeCfg.highlightFormatting) state.formatting = "code-block"; 267 state.code = 1 268 var returnType = getType(state); 269 state.code = 0 270 return returnType; 271 } 272 273 // Inline 274 function getType(state) { 275 var styles = []; 276 277 if (state.formatting) { 278 styles.push(tokenTypes.formatting); 279 280 if (typeof state.formatting === "string") state.formatting = [state.formatting]; 281 282 for (var i = 0; i < state.formatting.length; i++) { 283 styles.push(tokenTypes.formatting + "-" + state.formatting[i]); 284 285 if (state.formatting[i] === "header") { 286 styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.header); 287 } 288 289 // Add `formatting-quote` and `formatting-quote-#` for blockquotes 290 // Add `error` instead if the maximum blockquote nesting depth is passed 291 if (state.formatting[i] === "quote") { 292 if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) { 293 styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.quote); 294 } else { 295 styles.push("error"); 296 } 297 } 298 } 299 } 300 301 if (state.taskOpen) { 302 styles.push("meta"); 303 return styles.length ? styles.join(' ') : null; 304 } 305 if (state.taskClosed) { 306 styles.push("property"); 307 return styles.length ? styles.join(' ') : null; 308 } 309 310 if (state.linkHref) { 311 styles.push(tokenTypes.linkHref, "url"); 312 } else { // Only apply inline styles to non-url text 313 if (state.strong) { styles.push(tokenTypes.strong); } 314 if (state.em) { styles.push(tokenTypes.em); } 315 if (state.strikethrough) { styles.push(tokenTypes.strikethrough); } 316 if (state.linkText) { styles.push(tokenTypes.linkText); } 317 if (state.code) { styles.push(tokenTypes.code); } 318 if (state.image) { styles.push(tokenTypes.image); } 319 if (state.imageAltText) { styles.push(tokenTypes.imageAltText, "link"); } 320 if (state.imageMarker) { styles.push(tokenTypes.imageMarker); } 321 } 322 323 if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); } 324 325 if (state.quote) { 326 styles.push(tokenTypes.quote); 327 328 // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth 329 if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) { 330 styles.push(tokenTypes.quote + "-" + state.quote); 331 } else { 332 styles.push(tokenTypes.quote + "-" + modeCfg.maxBlockquoteDepth); 333 } 334 } 335 336 if (state.list !== false) { 337 var listMod = (state.listStack.length - 1) % 3; 338 if (!listMod) { 339 styles.push(tokenTypes.list1); 340 } else if (listMod === 1) { 341 styles.push(tokenTypes.list2); 342 } else { 343 styles.push(tokenTypes.list3); 344 } 345 } 346 347 if (state.trailingSpaceNewLine) { 348 styles.push("trailing-space-new-line"); 349 } else if (state.trailingSpace) { 350 styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b")); 351 } 352 353 return styles.length ? styles.join(' ') : null; 354 } 355 356 function handleText(stream, state) { 357 if (stream.match(textRE, true)) { 358 return getType(state); 359 } 360 return undefined; 361 } 362 363 function inlineNormal(stream, state) { 364 var style = state.text(stream, state); 365 if (typeof style !== 'undefined') 366 return style; 367 368 if (state.list) { // List marker (*, +, -, 1., etc) 369 state.list = null; 370 return getType(state); 371 } 372 373 if (state.taskList) { 374 var taskOpen = stream.match(taskListRE, true)[1] !== "x"; 375 if (taskOpen) state.taskOpen = true; 376 else state.taskClosed = true; 377 if (modeCfg.highlightFormatting) state.formatting = "task"; 378 state.taskList = false;
379 return getType(state); 380 } 381 382 state.taskOpen = false; 383 state.taskClosed = false; 384 385 if (state.header && stream.match(/^#+$/, true)) { 386 if (modeCfg.highlightFormatting) state.formatting = "header"; 387 return getType(state); 388 } 389 390 // Get sol() value now, before character is consumed 391 var sol = stream.sol(); 392 393 var ch = stream.next(); 394 395 // Matches link titles present on next line 396 if (state.linkTitle) { 397 state.linkTitle = false; 398 var matchCh = ch; 399 if (ch === '(') { 400 matchCh = ')'; 401 } 402 matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); 403 var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh; 404 if (stream.match(new RegExp(regex), true)) { 405 return tokenTypes.linkHref; 406 } 407 } 408 409 // If this block is changed, it may need to be updated in GFM mode 410 if (ch === '`') { 411 var previousFormatting = state.formatting; 412 if (modeCfg.highlightFormatting) state.formatting = "code"; 413 stream.eatWhile('`'); 414 var count = stream.current().length 415 if (state.code == 0) { 416 state.code = count 417 return getType(state) 418 } else if (count == state.code) { // Must be exact 419 var t = getType(state) 420 state.code = 0 421 return t 422 } else { 423 state.formatting = previousFormatting 424 return getType(state) 425 } 426 } else if (state.code) { 427 return getType(state); 428 } 429 430 if (ch === '\\') { 431 stream.next(); 432 if (modeCfg.highlightFormatting) { 433 var type = getType(state); 434 var formattingEscape = tokenTypes.formatting + "-escape"; 435 return type ? type + " " + formattingEscape : formattingEscape; 436 } 437 } 438 439 if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) { 440 state.imageMarker = true; 441 state.image = true; 442 if (modeCfg.highlightFormatting) state.formatting = "image"; 443 return getType(state); 444 } 445 446 if (ch === '[' && state.imageMarker) { 447 state.imageMarker = false;
448 state.imageAltText = true 449 if (modeCfg.highlightFormatting) state.formatting = "image"; 450 return getType(state); 451 } 452 453 if (ch === ']' && state.imageAltText) { 454 if (modeCfg.highlightFormatting) state.formatting = "image"; 455 var type = getType(state); 456 state.imageAltText = false; 457 state.image = false; 458 state.inline = state.f = linkHref; 459 return type; 460 } 461 462 if (ch === '[' && stream.match(/[^\]]*\](\(.*\)| ?\[.*?\])/, false) && !state.image) { 463 state.linkText = true; 464 if (modeCfg.highlightFormatting) state.formatting = "link"; 465 return getType(state); 466 } 467 468 if (ch === ']' && state.linkText && stream.match(/\(.*?\)| ?\[.*?\]/, false)) { 469 if (modeCfg.highlightFormatting) state.formatting = "link"; 470 var type = getType(state); 471 state.linkText = false; 472 state.inline = state.f = linkHref; 473 return type; 474 } 475 476 if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) { 477 state.f = state.inline = linkInline; 478 if (modeCfg.highlightFormatting) state.formatting = "link"; 479 var type = getType(state); 480 if (type){ 481 type += " "; 482 } else { 483 type = ""; 484 } 485 return type + tokenTypes.linkInline; 486 } 487 488 if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) { 489 state.f = state.inline = linkInline; 490 if (modeCfg.highlightFormatting) state.formatting = "link"; 491 var type = getType(state); 492 if (type){ 493 type += " "; 494 } else { 495 type = ""; 496 } 497 return type + tokenTypes.linkEmail; 498 } 499 500 if (ch === '<' && stream.match(/^(!--|\w)/, false)) { 501 var end = stream.string.indexOf(">", stream.pos); 502 if (end != -1) { 503 var atts = stream.string.substring(stream.start, end); 504 if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) state.md_inside = true; 505 } 506 stream.backUp(1); 507 state.htmlState = CodeMirror.startState(htmlMode); 508 return switchBlock(stream, state, htmlBlock); 509 } 510 511 if (ch === '<' && stream.match(/^\/\w*?>/)) { 512 state.md_inside = false;
513 return "tag"; 514 } 515 516 var ignoreUnderscore = false; 517 if (!modeCfg.underscoresBreakWords) { 518 if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) { 519 var prevPos = stream.pos - 2; 520 if (prevPos >= 0) { 521 var prevCh = stream.string.charAt(prevPos); 522 if (prevCh !== '_' && prevCh.match(/(\w)/, false)) { 523 ignoreUnderscore = true; 524 } 525 } 526 } 527 } 528 if (ch === '*' || (ch === '_' && !ignoreUnderscore)) { 529 if (sol && stream.peek() === ' ') { 530 // Do nothing, surrounded by newline and space 531 } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG 532 if (modeCfg.highlightFormatting) state.formatting = "strong"; 533 var t = getType(state); 534 state.strong = false; 535 return t; 536 } else if (!state.strong && stream.eat(ch)) { // Add STRONG 537 state.strong = ch; 538 if (modeCfg.highlightFormatting) state.formatting = "strong"; 539 return getType(state); 540 } else if (state.em === ch) { // Remove EM 541 if (modeCfg.highlightFormatting) state.formatting = "em"; 542 var t = getType(state); 543 state.em = false; 544 return t; 545 } else if (!state.em) { // Add EM 546 state.em = ch; 547 if (modeCfg.highlightFormatting) state.formatting = "em"; 548 return getType(state); 549 } 550 } else if (ch === ' ') { 551 if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces 552 if (stream.peek() === ' ') { // Surrounded by spaces, ignore 553 return getType(state); 554 } else { // Not surrounded by spaces, back up pointer 555 stream.backUp(1); 556 } 557 } 558 } 559 560 if (modeCfg.strikethrough) { 561 if (ch === '~' && stream.eatWhile(ch)) { 562 if (state.strikethrough) {// Remove strikethrough 563 if (modeCfg.highlightFormatting) state.formatting = "strikethrough"; 564 var t = getType(state); 565 state.strikethrough = false; 566 return t; 567 } else if (stream.match(/^[^\s]/, false)) {// Add strikethrough 568 state.strikethrough = true; 569 if (modeCfg.highlightFormatting) state.formatting = "strikethrough"; 570 return getType(state); 571 } 572 } else if (ch === ' ') { 573 if (stream.match(/^~~/, true)) { // Probably surrounded by space 574 if (stream.peek() === ' ') { // Surrounded by spaces, ignore 575 return getType(state); 576 } else { // Not surrounded by spaces, back up pointer 577 stream.backUp(2); 578 } 579 } 580 } 581 } 582 583 if (ch === ' ') { 584 if (stream.match(/ +$/, false)) { 585 state.trailingSpace++; 586 } else if (state.trailingSpace) { 587 state.trailingSpaceNewLine = true; 588 } 589 } 590 591 return getType(state); 592 } 593 594 function linkInline(stream, state) { 595 var ch = stream.next(); 596 597 if (ch === ">") { 598 state.f = state.inline = inlineNormal; 599 if (modeCfg.highlightFormatting) state.formatting = "link"; 600 var type = getType(state); 601 if (type){ 602 type += " "; 603 } else { 604 type = ""; 605 } 606 return type + tokenTypes.linkInline; 607 } 608 609 stream.match(/^[^>]+/, true); 610 611 return tokenTypes.linkInline; 612 } 613 614 function linkHref(stream, state) { 615 // Check if space, and return NULL if so (to avoid marking the space) 616 if(stream.eatSpace()){ 617 return null; 618 } 619 var ch = stream.next(); 620 if (ch === '(' || ch === '[') { 621 state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]", 0); 622 if (modeCfg.highlightFormatting) state.formatting = "link-string"; 623 state.linkHref = true; 624 return getType(state); 625 } 626 return 'error'; 627 } 628 629 var linkRE = { 630 ")": /^(?:[^\\\(\)]|\\.|\((?:[^\\\(\)]|\\.)*\))*?(?=\))/, 631 "]": /^(?:[^\\\[\]]|\\.|\[(?:[^\\\[\\]]|\\.)*\])*?(?=\])/ 632 } 633 634 function getLinkHrefInside(endChar) { 635 return function(stream, state) { 636 var ch = stream.next(); 637 638 if (ch === endChar) { 639 state.f = state.inline = inlineNormal; 640 if (modeCfg.highlightFormatting) state.formatting = "link-string"; 641 var returnState = getType(state); 642 state.linkHref = false;
643 return returnState; 644 } 645 646 stream.match(linkRE[endChar]) 647 state.linkHref = true; 648 return getType(state); 649 }; 650 } 651 652 function footnoteLink(stream, state) { 653 if (stream.match(/^([^\]\\]|\\.)*\]:/, false)) { 654 state.f = footnoteLinkInside; 655 stream.next(); // Consume [ 656 if (modeCfg.highlightFormatting) state.formatting = "link"; 657 state.linkText = true; 658 return getType(state); 659 } 660 return switchInline(stream, state, inlineNormal); 661 } 662 663 function footnoteLinkInside(stream, state) { 664 if (stream.match(/^\]:/, true)) { 665 state.f = state.inline = footnoteUrl; 666 if (modeCfg.highlightFormatting) state.formatting = "link"; 667 var returnType = getType(state); 668 state.linkText = false; 669 return returnType; 670 } 671 672 stream.match(/^([^\]\\]|\\.)+/, true); 673 674 return tokenTypes.linkText; 675 } 676 677 function footnoteUrl(stream, state) { 678 // Check if space, and return NULL if so (to avoid marking the space) 679 if(stream.eatSpace()){ 680 return null; 681 } 682 // Match URL 683 stream.match(/^[^\s]+/, true); 684 // Check for link title 685 if (stream.peek() === undefined) { // End of line, set flag to check next line 686 state.linkTitle = true; 687 } else { // More content on line, check if link title 688 stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true); 689 } 690 state.f = state.inline = inlineNormal; 691 return tokenTypes.linkHref + " url"; 692 } 693 694 var mode = { 695 startState: function() { 696 return { 697 f: blockNormal, 698 699 prevLine: null, 700 thisLine: null, 701 702 block: blockNormal, 703 htmlState: null, 704 indentation: 0, 705 706 inline: inlineNormal, 707 text: handleText, 708 709 formatting: false, 710 linkText: false, 711 linkHref: false, 712 linkTitle: false, 713 code: 0, 714 em: false, 715 strong: false, 716 header: 0, 717 hr: false, 718 taskList: false, 719 list: false, 720 listStack: [], 721 quote: 0, 722 trailingSpace: 0, 723 trailingSpaceNewLine: false, 724 strikethrough: false, 725 fencedChars: null 726 }; 727 }, 728 729 copyState: function(s) { 730 return { 731 f: s.f, 732 733 prevLine: s.prevLine, 734 thisLine: s.thisLine, 735 736 block: s.block, 737 htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState), 738 indentation: s.indentation, 739 740 localMode: s.localMode, 741 localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, 742 743 inline: s.inline, 744 text: s.text, 745 formatting: false, 746 linkTitle: s.linkTitle, 747 code: s.code, 748 em: s.em, 749 strong: s.strong, 750 strikethrough: s.strikethrough, 751 header: s.header, 752 hr: s.hr, 753 taskList: s.taskList, 754 list: s.list, 755 listStack: s.listStack.slice(0), 756 quote: s.quote, 757 indentedCode: s.indentedCode, 758 trailingSpace: s.trailingSpace, 759 trailingSpaceNewLine: s.trailingSpaceNewLine, 760 md_inside: s.md_inside, 761 fencedChars: s.fencedChars 762 }; 763 }, 764 765 token: function(stream, state) { 766 767 // Reset state.formatting 768 state.formatting = false; 769 770 if (stream != state.thisLine) { 771 var forceBlankLine = state.header || state.hr; 772 773 // Reset state.header and state.hr 774 state.header = 0; 775 state.hr = false; 776 777 if (stream.match(/^\s*$/, true) || forceBlankLine) { 778 blankLine(state); 779 if (!forceBlankLine) return null 780 state.prevLine = null 781 } 782 783 state.prevLine = state.thisLine 784 state.thisLine = stream 785 786 // Reset state.taskList 787 state.taskList = false; 788 789 // Reset state.trailingSpace 790 state.trailingSpace = 0; 791 state.trailingSpaceNewLine = false; 792 793 state.f = state.block; 794 var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; 795 state.indentationDiff = Math.min(indentation - state.indentation, 4); 796 state.indentation = state.indentation + state.indentationDiff; 797 if (indentation > 0) return null; 798 } 799 return state.f(stream, state); 800 }, 801 802 innerMode: function(state) { 803 if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode}; 804 if (state.localState) return {state: state.localState, mode: state.localMode}; 805 return {state: state, mode: mode}; 806 }, 807 808 blankLine: blankLine, 809 810 getType: getType, 811 812 fold: "markdown" 813 }; 814 return mode; 815}, "xml"); 816 817CodeMirror.defineMIME("text/x-markdown", "markdown"); 818 819});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.