Mercurial
comparison .cms/lib/codemirror/mode/haml/haml.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others | |
2 // Distributed under an MIT license: https://codemirror.net/5/LICENSE | |
3 | |
4 (function(mod) { | |
5 if (typeof exports == "object" && typeof module == "object") // CommonJS | |
6 mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby")); | |
7 else if (typeof define == "function" && define.amd) // AMD | |
8 define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../ruby/ruby"], mod); | |
9 else // Plain browser env | |
10 mod(CodeMirror); | |
11 })(function(CodeMirror) { | |
12 "use strict"; | |
13 | |
14 // full haml mode. This handled embedded ruby and html fragments too | |
15 CodeMirror.defineMode("haml", function(config) { | |
16 var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); | |
17 var rubyMode = CodeMirror.getMode(config, "ruby"); | |
18 | |
19 function rubyInQuote(endQuote) { | |
20 return function(stream, state) { | |
21 var ch = stream.peek(); | |
22 if (ch == endQuote && state.rubyState.tokenize.length == 1) { | |
23 // step out of ruby context as it seems to complete processing all the braces | |
24 stream.next(); | |
25 state.tokenize = html; | |
26 return "closeAttributeTag"; | |
27 } else { | |
28 return ruby(stream, state); | |
29 } | |
30 }; | |
31 } | |
32 | |
33 function ruby(stream, state) { | |
34 if (stream.match("-#")) { | |
35 stream.skipToEnd(); | |
36 return "comment"; | |
37 } | |
38 return rubyMode.token(stream, state.rubyState); | |
39 } | |
40 | |
41 function html(stream, state) { | |
42 var ch = stream.peek(); | |
43 | |
44 // handle haml declarations. All declarations that cant be handled here | |
45 // will be passed to html mode | |
46 if (state.previousToken.style == "comment" ) { | |
47 if (state.indented > state.previousToken.indented) { | |
48 stream.skipToEnd(); | |
49 return "commentLine"; | |
50 } | |
51 } | |
52 | |
53 if (state.startOfLine) { | |
54 if (ch == "!" && stream.match("!!")) { | |
55 stream.skipToEnd(); | |
56 return "tag"; | |
57 } else if (stream.match(/^%[\w:#\.]+=/)) { | |
58 state.tokenize = ruby; | |
59 return "hamlTag"; | |
60 } else if (stream.match(/^%[\w:]+/)) { | |
61 return "hamlTag"; | |
62 } else if (ch == "/" ) { | |
63 stream.skipToEnd(); | |
64 return "comment"; | |
65 } | |
66 } | |
67 | |
68 if (state.startOfLine || state.previousToken.style == "hamlTag") { | |
69 if ( ch == "#" || ch == ".") { | |
70 stream.match(/[\w-#\.]*/); | |
71 return "hamlAttribute"; | |
72 } | |
73 } | |
74 | |
75 // do not handle --> as valid ruby, make it HTML close comment instead | |
76 if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) { | |
77 state.tokenize = ruby; | |
78 return state.tokenize(stream, state); | |
79 } | |
80 | |
81 if (state.previousToken.style == "hamlTag" || | |
82 state.previousToken.style == "closeAttributeTag" || | |
83 state.previousToken.style == "hamlAttribute") { | |
84 if (ch == "(") { | |
85 state.tokenize = rubyInQuote(")"); | |
86 return state.tokenize(stream, state); | |
87 } else if (ch == "{") { | |
88 if (!stream.match(/^\{%.*/)) { | |
89 state.tokenize = rubyInQuote("}"); | |
90 return state.tokenize(stream, state); | |
91 } | |
92 } | |
93 } | |
94 | |
95 return htmlMode.token(stream, state.htmlState); | |
96 } | |
97 | |
98 return { | |
99 // default to html mode | |
100 startState: function() { | |
101 var htmlState = CodeMirror.startState(htmlMode); | |
102 var rubyState = CodeMirror.startState(rubyMode); | |
103 return { | |
104 htmlState: htmlState, | |
105 rubyState: rubyState, | |
106 indented: 0, | |
107 previousToken: { style: null, indented: 0}, | |
108 tokenize: html | |
109 }; | |
110 }, | |
111 | |
112 copyState: function(state) { | |
113 return { | |
114 htmlState : CodeMirror.copyState(htmlMode, state.htmlState), | |
115 rubyState: CodeMirror.copyState(rubyMode, state.rubyState), | |
116 indented: state.indented, | |
117 previousToken: state.previousToken, | |
118 tokenize: state.tokenize | |
119 }; | |
120 }, | |
121 | |
122 token: function(stream, state) { | |
123 if (stream.sol()) { | |
124 state.indented = stream.indentation(); | |
125 state.startOfLine = true; | |
126 } | |
127 if (stream.eatSpace()) return null; | |
128 var style = state.tokenize(stream, state); | |
129 state.startOfLine = false; | |
130 // dont record comment line as we only want to measure comment line with | |
131 // the opening comment block | |
132 if (style && style != "commentLine") { | |
133 state.previousToken = { style: style, indented: state.indented }; | |
134 } | |
135 // if current state is ruby and the previous token is not `,` reset the | |
136 // tokenize to html | |
137 if (stream.eol() && state.tokenize == ruby) { | |
138 stream.backUp(1); | |
139 var ch = stream.peek(); | |
140 stream.next(); | |
141 if (ch && ch != ",") { | |
142 state.tokenize = html; | |
143 } | |
144 } | |
145 // reprocess some of the specific style tag when finish setting previousToken | |
146 if (style == "hamlTag") { | |
147 style = "tag"; | |
148 } else if (style == "commentLine") { | |
149 style = "comment"; | |
150 } else if (style == "hamlAttribute") { | |
151 style = "attribute"; | |
152 } else if (style == "closeAttributeTag") { | |
153 style = null; | |
154 } | |
155 return style; | |
156 } | |
157 }; | |
158 }, "htmlmixed", "ruby"); | |
159 | |
160 CodeMirror.defineMIME("text/x-haml", "haml"); | |
161 }); |