mbox.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. (function(mod) {
  4. if (typeof exports == "object" && typeof module == "object") // CommonJS
  5. mod(require("../../lib/codemirror"));
  6. else if (typeof define == "function" && define.amd) // AMD
  7. define(["../../lib/codemirror"], mod);
  8. else // Plain browser env
  9. mod(CodeMirror);
  10. })(function(CodeMirror) {
  11. "use strict";
  12. var rfc2822 = [
  13. "From", "Sender", "Reply-To", "To", "Cc", "Bcc", "Message-ID",
  14. "In-Reply-To", "References", "Resent-From", "Resent-Sender", "Resent-To",
  15. "Resent-Cc", "Resent-Bcc", "Resent-Message-ID", "Return-Path", "Received"
  16. ];
  17. var rfc2822NoEmail = [
  18. "Date", "Subject", "Comments", "Keywords", "Resent-Date"
  19. ];
  20. CodeMirror.registerHelper("hintWords", "mbox", rfc2822.concat(rfc2822NoEmail));
  21. var whitespace = /^[ \t]/;
  22. var separator = /^From /; // See RFC 4155
  23. var rfc2822Header = new RegExp("^(" + rfc2822.join("|") + "): ");
  24. var rfc2822HeaderNoEmail = new RegExp("^(" + rfc2822NoEmail.join("|") + "): ");
  25. var header = /^[^:]+:/; // Optional fields defined in RFC 2822
  26. var email = /^[^ ]+@[^ ]+/;
  27. var untilEmail = /^.*?(?=[^ ]+?@[^ ]+)/;
  28. var bracketedEmail = /^<.*?>/;
  29. var untilBracketedEmail = /^.*?(?=<.*>)/;
  30. function styleForHeader(header) {
  31. if (header === "Subject") return "header";
  32. return "string";
  33. }
  34. function readToken(stream, state) {
  35. if (stream.sol()) {
  36. // From last line
  37. state.inSeparator = false;
  38. if (state.inHeader && stream.match(whitespace)) {
  39. // Header folding
  40. return null;
  41. } else {
  42. state.inHeader = false;
  43. state.header = null;
  44. }
  45. if (stream.match(separator)) {
  46. state.inHeaders = true;
  47. state.inSeparator = true;
  48. return "atom";
  49. }
  50. var match;
  51. var emailPermitted = false;
  52. if ((match = stream.match(rfc2822HeaderNoEmail)) ||
  53. (emailPermitted = true) && (match = stream.match(rfc2822Header))) {
  54. state.inHeaders = true;
  55. state.inHeader = true;
  56. state.emailPermitted = emailPermitted;
  57. state.header = match[1];
  58. return "atom";
  59. }
  60. // Use vim's heuristics: recognize custom headers only if the line is in a
  61. // block of legitimate headers.
  62. if (state.inHeaders && (match = stream.match(header))) {
  63. state.inHeader = true;
  64. state.emailPermitted = true;
  65. state.header = match[1];
  66. return "atom";
  67. }
  68. state.inHeaders = false;
  69. stream.skipToEnd();
  70. return null;
  71. }
  72. if (state.inSeparator) {
  73. if (stream.match(email)) return "link";
  74. if (stream.match(untilEmail)) return "atom";
  75. stream.skipToEnd();
  76. return "atom";
  77. }
  78. if (state.inHeader) {
  79. var style = styleForHeader(state.header);
  80. if (state.emailPermitted) {
  81. if (stream.match(bracketedEmail)) return style + " link";
  82. if (stream.match(untilBracketedEmail)) return style;
  83. }
  84. stream.skipToEnd();
  85. return style;
  86. }
  87. stream.skipToEnd();
  88. return null;
  89. };
  90. CodeMirror.defineMode("mbox", function() {
  91. return {
  92. startState: function() {
  93. return {
  94. // Is in a mbox separator
  95. inSeparator: false,
  96. // Is in a mail header
  97. inHeader: false,
  98. // If bracketed email is permitted. Only applicable when inHeader
  99. emailPermitted: false,
  100. // Name of current header
  101. header: null,
  102. // Is in a region of mail headers
  103. inHeaders: false
  104. };
  105. },
  106. token: readToken,
  107. blankLine: function(state) {
  108. state.inHeaders = state.inSeparator = state.inHeader = false;
  109. }
  110. };
  111. });
  112. CodeMirror.defineMIME("application/mbox", "mbox");
  113. });