scripts/CodeMirror/mode/mbox/mbox.js (view raw)
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
14var 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];
19var rfc2822NoEmail = [
20 "Date", "Subject", "Comments", "Keywords", "Resent-Date"
21];
22
23CodeMirror.registerHelper("hintWords", "mbox", rfc2822.concat(rfc2822NoEmail));
24
25var whitespace = /^[ \t]/;
26var separator = /^From /; // See RFC 4155
27var rfc2822Header = new RegExp("^(" + rfc2822.join("|") + "): ");
28var rfc2822HeaderNoEmail = new RegExp("^(" + rfc2822NoEmail.join("|") + "): ");
29var header = /^[^:]+:/; // Optional fields defined in RFC 2822
30var email = /^[^ ]+@[^ ]+/;
31var untilEmail = /^.*?(?=[^ ]+?@[^ ]+)/;
32var bracketedEmail = /^<.*?>/;
33var untilBracketedEmail = /^.*?(?=<.*>)/;
34
35function styleForHeader(header) {
36 if (header === "Subject") return "header";
37 return "string";
38}
39
40function 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
105CodeMirror.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
128CodeMirror.defineMIME("application/mbox", "mbox");
129});