CodeMirror.defineMode("yaml", function() {
	
	var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];
	var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i');
	
	return {
		token: function(stream, state) {
			var ch = stream.peek();
			var esc = state.escaped;
			state.escaped = false;
			/* comments */
			if (ch == "#") { stream.skipToEnd(); return "comment"; }
			if (state.literal && stream.indentation() > state.keyCol) {
				stream.skipToEnd(); return "string";
			} else if (state.literal) { state.literal = false; }
			if (stream.sol()) {
				state.keyCol = 0;
				state.pair = false;
				state.pairStart = false;
				/* document start */
				if(stream.match(/---/)) { return "def"; }
				/* document end */
				if (stream.match(/\.\.\./)) { return "def"; }
				/* array list item */
				if (stream.match(/\s*-\s+/)) { return 'meta'; }
			}
			/* pairs (associative arrays) -> key */
			if (!state.pair && stream.match(/^\s*([a-z0-9\._-])+(?=\s*:)/i)) {
				state.pair = true;
				state.keyCol = stream.indentation();
				return "atom";
			}
			if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; }
			
			/* inline pairs/lists */
			if (stream.match(/^(\{|\}|\[|\])/)) {
				if (ch == '{')
					state.inlinePairs++;
				else if (ch == '}')
					state.inlinePairs--;
				else if (ch == '[')
					state.inlineList++;
				else
					state.inlineList--;
				return 'meta';
			}
			
			/* list seperator */
			if (state.inlineList > 0 && !esc && ch == ',') {
				stream.next();
				return 'meta';
			}
			/* pairs seperator */
			if (state.inlinePairs > 0 && !esc && ch == ',') {
				state.keyCol = 0;
				state.pair = false;
				state.pairStart = false;
				stream.next();
				return 'meta';
			}
			
			/* start of value of a pair */
			if (state.pairStart) {
				/* block literals */
				if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; };
				/* references */
				if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; }
				/* numbers */
				if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; }
				if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; }
				/* keywords */
				if (stream.match(keywordRegex)) { return 'keyword'; }
			}

			/* nothing found, continue */
			state.pairStart = false;
			state.escaped = (ch == '\\');
			stream.next();
			return null;
		},
		startState: function() {
			return {
				pair: false,
				pairStart: false,
				keyCol: 0,
				inlinePairs: 0,
				inlineList: 0,
				literal: false,
				escaped: false
			};
		}
	};
});

CodeMirror.defineMIME("text/x-yaml", "yaml");
