mbox.js 4.4 KB

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