6 #include "utf8_string.hpp"
10 Emitter::Emitter(struct Sass_Output_Options& opt)
15 scheduled_linefeed(0),
16 scheduled_delimiter(false),
20 in_media_block(false),
21 in_declaration(false),
22 in_space_array(false),
26 // return buffer as string
27 std::string Emitter::get_buffer(void)
32 Sass_Output_Style Emitter::output_style(void) const
34 return opt.output_style;
37 // PROXY METHODS FOR SOURCE MAPS
39 void Emitter::add_source_index(size_t idx)
40 { wbuf.smap.source_index.push_back(idx); }
42 std::string Emitter::render_srcmap(Context &ctx)
43 { return wbuf.smap.render_srcmap(ctx); }
45 void Emitter::set_filename(const std::string& str)
46 { wbuf.smap.file = str; }
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); }
57 // MAIN BUFFER MANIPULATION
59 // add outstanding delimiter
60 void Emitter::finalize(bool final)
63 if (output_style() == SASS_STYLE_COMPRESSED)
64 if (final) scheduled_delimiter = false;
65 if (scheduled_linefeed)
66 scheduled_linefeed = 1;
70 // flush scheduled space/linefeed
71 void Emitter::flush_schedules(void)
74 if (scheduled_linefeed) {
75 std::string linefeeds = "";
77 for (size_t i = 0; i < scheduled_linefeed; i++)
78 linefeeds += opt.linefeed;
80 scheduled_linefeed = 0;
81 append_string(linefeeds);
83 } else if (scheduled_space) {
84 std::string spaces(scheduled_space, ' ');
86 append_string(spaces);
88 if (scheduled_delimiter) {
89 scheduled_delimiter = false;
94 // prepend some text or token to the buffer
95 void Emitter::prepend_output(const OutputBuffer& output)
97 wbuf.smap.prepend(output);
98 wbuf.buffer = output.buffer + wbuf.buffer;
101 // prepend some text or token to the buffer
102 void Emitter::prepend_string(const std::string& text)
104 wbuf.smap.prepend(Offset(text));
105 wbuf.buffer = text + wbuf.buffer;
108 // append some text or token to the buffer
109 void Emitter::append_string(const std::string& text)
115 if (in_comment && output_style() == COMPACT) {
116 // unescape comment nodes
117 std::string out = comment_to_string(text);
120 // account for data in source-maps
121 wbuf.smap.append(Offset(out));
125 // account for data in source-maps
126 wbuf.smap.append(Offset(text));
130 // append some white-space only text
131 void Emitter::append_wspace(const std::string& text)
133 if (text.empty()) return;
134 if (peek_linefeed(text.c_str())) {
136 append_mandatory_linefeed();
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)
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;
153 add_close_mapping(node);
158 void Emitter::append_indentation()
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);
171 void Emitter::append_delimiter()
173 scheduled_delimiter = true;
174 if (output_style() == COMPACT) {
175 if (indentation == 0) {
176 append_mandatory_linefeed();
178 append_mandatory_space();
180 } else if (output_style() != COMPRESSED) {
181 append_optional_linefeed();
185 void Emitter::append_comma_separator()
187 // scheduled_space = 0;
189 append_optional_space();
192 void Emitter::append_colon_separator()
196 append_optional_space();
199 void Emitter::append_mandatory_space()
204 void Emitter::append_optional_space()
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();
214 void Emitter::append_special_linefeed()
216 if (output_style() == COMPACT) {
217 append_mandatory_linefeed();
218 for (size_t p = 0; p < indentation; p++)
219 append_string(opt.indent);
223 void Emitter::append_optional_linefeed()
225 if (in_declaration && in_comma_array) return;
226 if (output_style() == COMPACT) {
227 append_mandatory_space();
229 append_mandatory_linefeed();
233 void Emitter::append_mandatory_linefeed()
235 if (output_style() != COMPRESSED) {
236 scheduled_linefeed = 1;
238 // flush_schedules();
242 void Emitter::append_scope_opener(AST_Node_Ptr node)
244 scheduled_linefeed = 0;
245 append_optional_space();
247 if (node) add_open_mapping(node);
249 append_optional_linefeed();
250 // append_optional_space();
253 void Emitter::append_scope_closer(AST_Node_Ptr node)
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();
263 append_optional_space();
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;