Initial commit
[yaffs-website] / node_modules / node-sass / src / libsass / src / emitter.cpp
1 #include "sass.hpp"
2 #include "util.hpp"
3 #include "context.hpp"
4 #include "output.hpp"
5 #include "emitter.hpp"
6 #include "utf8_string.hpp"
7
8 namespace Sass {
9
10   Emitter::Emitter(struct Sass_Output_Options& opt)
11   : wbuf(),
12     opt(opt),
13     indentation(0),
14     scheduled_space(0),
15     scheduled_linefeed(0),
16     scheduled_delimiter(false),
17     scheduled_mapping(0),
18     in_comment(false),
19     in_wrapped(false),
20     in_media_block(false),
21     in_declaration(false),
22     in_space_array(false),
23     in_comma_array(false)
24   { }
25
26   // return buffer as string
27   std::string Emitter::get_buffer(void)
28   {
29     return wbuf.buffer;
30   }
31
32   Sass_Output_Style Emitter::output_style(void) const
33   {
34     return opt.output_style;
35   }
36
37   // PROXY METHODS FOR SOURCE MAPS
38
39   void Emitter::add_source_index(size_t idx)
40   { wbuf.smap.source_index.push_back(idx); }
41
42   std::string Emitter::render_srcmap(Context &ctx)
43   { return wbuf.smap.render_srcmap(ctx); }
44
45   void Emitter::set_filename(const std::string& str)
46   { wbuf.smap.file = str; }
47
48   void Emitter::schedule_mapping(const AST_Node_Ptr node)
49   { scheduled_mapping = node; }
50   void Emitter::add_open_mapping(const AST_Node_Ptr node)
51   { wbuf.smap.add_open_mapping(node); }
52   void Emitter::add_close_mapping(const AST_Node_Ptr node)
53   { wbuf.smap.add_close_mapping(node); }
54   ParserState Emitter::remap(const ParserState& pstate)
55   { return wbuf.smap.remap(pstate); }
56
57   // MAIN BUFFER MANIPULATION
58
59   // add outstanding delimiter
60   void Emitter::finalize(bool final)
61   {
62     scheduled_space = 0;
63     if (output_style() == SASS_STYLE_COMPRESSED)
64       if (final) scheduled_delimiter = false;
65     if (scheduled_linefeed)
66       scheduled_linefeed = 1;
67     flush_schedules();
68   }
69
70   // flush scheduled space/linefeed
71   void Emitter::flush_schedules(void)
72   {
73     // check the schedule
74     if (scheduled_linefeed) {
75       std::string linefeeds = "";
76
77       for (size_t i = 0; i < scheduled_linefeed; i++)
78         linefeeds += opt.linefeed;
79       scheduled_space = 0;
80       scheduled_linefeed = 0;
81       append_string(linefeeds);
82
83     } else if (scheduled_space) {
84       std::string spaces(scheduled_space, ' ');
85       scheduled_space = 0;
86       append_string(spaces);
87     }
88     if (scheduled_delimiter) {
89       scheduled_delimiter = false;
90       append_string(";");
91     }
92   }
93
94   // prepend some text or token to the buffer
95   void Emitter::prepend_output(const OutputBuffer& output)
96   {
97     wbuf.smap.prepend(output);
98     wbuf.buffer = output.buffer + wbuf.buffer;
99   }
100
101   // prepend some text or token to the buffer
102   void Emitter::prepend_string(const std::string& text)
103   {
104     wbuf.smap.prepend(Offset(text));
105     wbuf.buffer = text + wbuf.buffer;
106   }
107
108   // append some text or token to the buffer
109   void Emitter::append_string(const std::string& text)
110   {
111
112     // write space/lf
113     flush_schedules();
114
115     if (in_comment && output_style() == COMPACT) {
116       // unescape comment nodes
117       std::string out = comment_to_string(text);
118       // add to buffer
119       wbuf.buffer += out;
120       // account for data in source-maps
121       wbuf.smap.append(Offset(out));
122     } else {
123       // add to buffer
124       wbuf.buffer += text;
125       // account for data in source-maps
126       wbuf.smap.append(Offset(text));
127     }
128   }
129
130   // append some white-space only text
131   void Emitter::append_wspace(const std::string& text)
132   {
133     if (text.empty()) return;
134     if (peek_linefeed(text.c_str())) {
135       scheduled_space = 0;
136       append_mandatory_linefeed();
137     }
138   }
139
140   // append some text or token to the buffer
141   // this adds source-mappings for node start and end
142   void Emitter::append_token(const std::string& text, const AST_Node_Ptr node)
143   {
144     flush_schedules();
145     add_open_mapping(node);
146     // hotfix for browser issues
147     // this is pretty ugly indeed
148     if (scheduled_mapping) {
149       add_open_mapping(scheduled_mapping);
150       scheduled_mapping = 0;
151     }
152     append_string(text);
153     add_close_mapping(node);
154   }
155
156   // HELPER METHODS
157
158   void Emitter::append_indentation()
159   {
160     if (output_style() == COMPRESSED) return;
161     if (output_style() == COMPACT) return;
162     if (in_declaration && in_comma_array) return;
163     if (scheduled_linefeed && indentation)
164       scheduled_linefeed = 1;
165     std::string indent = "";
166     for (size_t i = 0; i < indentation; i++)
167       indent += opt.indent;
168     append_string(indent);
169   }
170
171   void Emitter::append_delimiter()
172   {
173     scheduled_delimiter = true;
174     if (output_style() == COMPACT) {
175       if (indentation == 0) {
176         append_mandatory_linefeed();
177       } else {
178         append_mandatory_space();
179       }
180     } else if (output_style() != COMPRESSED) {
181       append_optional_linefeed();
182     }
183   }
184
185   void Emitter::append_comma_separator()
186   {
187     // scheduled_space = 0;
188     append_string(",");
189     append_optional_space();
190   }
191
192   void Emitter::append_colon_separator()
193   {
194     scheduled_space = 0;
195     append_string(":");
196     append_optional_space();
197   }
198
199   void Emitter::append_mandatory_space()
200   {
201     scheduled_space = 1;
202   }
203
204   void Emitter::append_optional_space()
205   {
206     if ((output_style() != COMPRESSED) && buffer().size()) {
207       unsigned char lst = buffer().at(buffer().length() - 1);
208       if (!isspace(lst) || scheduled_delimiter) {
209         append_mandatory_space();
210       }
211     }
212   }
213
214   void Emitter::append_special_linefeed()
215   {
216     if (output_style() == COMPACT) {
217       append_mandatory_linefeed();
218       for (size_t p = 0; p < indentation; p++)
219         append_string(opt.indent);
220     }
221   }
222
223   void Emitter::append_optional_linefeed()
224   {
225     if (in_declaration && in_comma_array) return;
226     if (output_style() == COMPACT) {
227       append_mandatory_space();
228     } else {
229       append_mandatory_linefeed();
230     }
231   }
232
233   void Emitter::append_mandatory_linefeed()
234   {
235     if (output_style() != COMPRESSED) {
236       scheduled_linefeed = 1;
237       scheduled_space = 0;
238       // flush_schedules();
239     }
240   }
241
242   void Emitter::append_scope_opener(AST_Node_Ptr node)
243   {
244     scheduled_linefeed = 0;
245     append_optional_space();
246     flush_schedules();
247     if (node) add_open_mapping(node);
248     append_string("{");
249     append_optional_linefeed();
250     // append_optional_space();
251     ++ indentation;
252   }
253   void Emitter::append_scope_closer(AST_Node_Ptr node)
254   {
255     -- indentation;
256     scheduled_linefeed = 0;
257     if (output_style() == COMPRESSED)
258       scheduled_delimiter = false;
259     if (output_style() == EXPANDED) {
260       append_optional_linefeed();
261       append_indentation();
262     } else {
263       append_optional_space();
264     }
265     append_string("}");
266     if (node) add_close_mapping(node);
267     append_optional_linefeed();
268     if (indentation != 0) return;
269     if (output_style() != COMPRESSED)
270       scheduled_linefeed = 2;
271   }
272
273 }