| 
									
										
										
										
											2018-01-21 10:33:32 -05:00
										 |  |  | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 | 
					
						
							| 
									
										
										
										
											2018-10-07 12:02:07 +02:00
										 |  |  | // Distributed under an MIT license: https://codemirror.net/LICENSE
 | 
					
						
							| 
									
										
										
										
											2018-01-21 10:33:32 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | (function(mod) { | 
					
						
							|  |  |  |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 | 
					
						
							|  |  |  |     mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby")); | 
					
						
							|  |  |  |   else if (typeof define == "function" && define.amd) // AMD
 | 
					
						
							|  |  |  |     define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../ruby/ruby"], mod); | 
					
						
							|  |  |  |   else // Plain browser env
 | 
					
						
							|  |  |  |     mod(CodeMirror); | 
					
						
							|  |  |  | })(function(CodeMirror) { | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // full haml mode. This handled embedded ruby and html fragments too
 | 
					
						
							|  |  |  |   CodeMirror.defineMode("haml", function(config) { | 
					
						
							|  |  |  |     var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); | 
					
						
							|  |  |  |     var rubyMode = CodeMirror.getMode(config, "ruby"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function rubyInQuote(endQuote) { | 
					
						
							|  |  |  |       return function(stream, state) { | 
					
						
							|  |  |  |         var ch = stream.peek(); | 
					
						
							|  |  |  |         if (ch == endQuote && state.rubyState.tokenize.length == 1) { | 
					
						
							|  |  |  |           // step out of ruby context as it seems to complete processing all the braces
 | 
					
						
							|  |  |  |           stream.next(); | 
					
						
							|  |  |  |           state.tokenize = html; | 
					
						
							|  |  |  |           return "closeAttributeTag"; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           return ruby(stream, state); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function ruby(stream, state) { | 
					
						
							|  |  |  |       if (stream.match("-#")) { | 
					
						
							|  |  |  |         stream.skipToEnd(); | 
					
						
							|  |  |  |         return "comment"; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return rubyMode.token(stream, state.rubyState); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function html(stream, state) { | 
					
						
							|  |  |  |       var ch = stream.peek(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // handle haml declarations. All declarations that cant be handled here
 | 
					
						
							|  |  |  |       // will be passed to html mode
 | 
					
						
							|  |  |  |       if (state.previousToken.style == "comment" ) { | 
					
						
							|  |  |  |         if (state.indented > state.previousToken.indented) { | 
					
						
							|  |  |  |           stream.skipToEnd(); | 
					
						
							|  |  |  |           return "commentLine"; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (state.startOfLine) { | 
					
						
							|  |  |  |         if (ch == "!" && stream.match("!!")) { | 
					
						
							|  |  |  |           stream.skipToEnd(); | 
					
						
							|  |  |  |           return "tag"; | 
					
						
							|  |  |  |         } else if (stream.match(/^%[\w:#\.]+=/)) { | 
					
						
							|  |  |  |           state.tokenize = ruby; | 
					
						
							|  |  |  |           return "hamlTag"; | 
					
						
							|  |  |  |         } else if (stream.match(/^%[\w:]+/)) { | 
					
						
							|  |  |  |           return "hamlTag"; | 
					
						
							|  |  |  |         } else if (ch == "/" ) { | 
					
						
							|  |  |  |           stream.skipToEnd(); | 
					
						
							|  |  |  |           return "comment"; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (state.startOfLine || state.previousToken.style == "hamlTag") { | 
					
						
							|  |  |  |         if ( ch == "#" || ch == ".") { | 
					
						
							|  |  |  |           stream.match(/[\w-#\.]*/); | 
					
						
							|  |  |  |           return "hamlAttribute"; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-06 22:16:34 +02:00
										 |  |  |       // do not handle --> as valid ruby, make it HTML close comment instead
 | 
					
						
							| 
									
										
										
										
											2018-01-21 10:33:32 -05:00
										 |  |  |       if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) { | 
					
						
							|  |  |  |         state.tokenize = ruby; | 
					
						
							|  |  |  |         return state.tokenize(stream, state); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (state.previousToken.style == "hamlTag" || | 
					
						
							|  |  |  |           state.previousToken.style == "closeAttributeTag" || | 
					
						
							|  |  |  |           state.previousToken.style == "hamlAttribute") { | 
					
						
							|  |  |  |         if (ch == "(") { | 
					
						
							|  |  |  |           state.tokenize = rubyInQuote(")"); | 
					
						
							|  |  |  |           return state.tokenize(stream, state); | 
					
						
							|  |  |  |         } else if (ch == "{") { | 
					
						
							|  |  |  |           if (!stream.match(/^\{%.*/)) { | 
					
						
							|  |  |  |             state.tokenize = rubyInQuote("}"); | 
					
						
							|  |  |  |             return state.tokenize(stream, state); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return htmlMode.token(stream, state.htmlState); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       // default to html mode
 | 
					
						
							|  |  |  |       startState: function() { | 
					
						
							|  |  |  |         var htmlState = CodeMirror.startState(htmlMode); | 
					
						
							|  |  |  |         var rubyState = CodeMirror.startState(rubyMode); | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |           htmlState: htmlState, | 
					
						
							|  |  |  |           rubyState: rubyState, | 
					
						
							|  |  |  |           indented: 0, | 
					
						
							|  |  |  |           previousToken: { style: null, indented: 0}, | 
					
						
							|  |  |  |           tokenize: html | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       copyState: function(state) { | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |           htmlState : CodeMirror.copyState(htmlMode, state.htmlState), | 
					
						
							|  |  |  |           rubyState: CodeMirror.copyState(rubyMode, state.rubyState), | 
					
						
							|  |  |  |           indented: state.indented, | 
					
						
							|  |  |  |           previousToken: state.previousToken, | 
					
						
							|  |  |  |           tokenize: state.tokenize | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       token: function(stream, state) { | 
					
						
							|  |  |  |         if (stream.sol()) { | 
					
						
							|  |  |  |           state.indented = stream.indentation(); | 
					
						
							|  |  |  |           state.startOfLine = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (stream.eatSpace()) return null; | 
					
						
							|  |  |  |         var style = state.tokenize(stream, state); | 
					
						
							|  |  |  |         state.startOfLine = false; | 
					
						
							|  |  |  |         // dont record comment line as we only want to measure comment line with
 | 
					
						
							|  |  |  |         // the opening comment block
 | 
					
						
							|  |  |  |         if (style && style != "commentLine") { | 
					
						
							|  |  |  |           state.previousToken = { style: style, indented: state.indented }; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // if current state is ruby and the previous token is not `,` reset the
 | 
					
						
							|  |  |  |         // tokenize to html
 | 
					
						
							|  |  |  |         if (stream.eol() && state.tokenize == ruby) { | 
					
						
							|  |  |  |           stream.backUp(1); | 
					
						
							|  |  |  |           var ch = stream.peek(); | 
					
						
							|  |  |  |           stream.next(); | 
					
						
							|  |  |  |           if (ch && ch != ",") { | 
					
						
							|  |  |  |             state.tokenize = html; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // reprocess some of the specific style tag when finish setting previousToken
 | 
					
						
							|  |  |  |         if (style == "hamlTag") { | 
					
						
							|  |  |  |           style = "tag"; | 
					
						
							|  |  |  |         } else if (style == "commentLine") { | 
					
						
							|  |  |  |           style = "comment"; | 
					
						
							|  |  |  |         } else if (style == "hamlAttribute") { | 
					
						
							|  |  |  |           style = "attribute"; | 
					
						
							|  |  |  |         } else if (style == "closeAttributeTag") { | 
					
						
							|  |  |  |           style = null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return style; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }, "htmlmixed", "ruby"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CodeMirror.defineMIME("text/x-haml", "haml"); | 
					
						
							|  |  |  | }); |