|
Packit Service |
7770af |
#include "sass.hpp"
|
|
Packit Service |
7770af |
#include "ast.hpp"
|
|
Packit Service |
7770af |
#include "output.hpp"
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
namespace Sass {
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Output::Output(Sass_Output_Options& opt)
|
|
Packit Service |
7770af |
: Inspect(Emitter(opt)),
|
|
Packit Service |
7770af |
charset(""),
|
|
Packit Service |
7770af |
top_nodes(0)
|
|
Packit Service |
7770af |
{}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Output::~Output() { }
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::fallback_impl(AST_Node_Ptr n)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
return n->perform(this);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(Number_Ptr n)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// use values to_string facility
|
|
Packit Service |
7770af |
std::string res = n->to_string(opt);
|
|
Packit Service |
7770af |
// check for a valid unit here
|
|
Packit Service |
7770af |
// includes result for reporting
|
|
Packit Service |
7770af |
if (!n->is_valid_css_unit()) {
|
|
Packit Service |
7770af |
throw Exception::InvalidValue(*n);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// output the final token
|
|
Packit Service |
7770af |
append_token(res, n);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(Import_Ptr imp)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
top_nodes.push_back(imp);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(Map_Ptr m)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
std::string dbg(m->to_string(opt));
|
|
Packit Service |
7770af |
error(dbg + " isn't a valid CSS value.", m->pstate());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
OutputBuffer Output::get_buffer(void)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Emitter emitter(opt);
|
|
Packit Service |
7770af |
Inspect inspect(emitter);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
size_t size_nodes = top_nodes.size();
|
|
Packit Service |
7770af |
for (size_t i = 0; i < size_nodes; i++) {
|
|
Packit Service |
7770af |
top_nodes[i]->perform(&inspect);
|
|
Packit Service |
7770af |
inspect.append_mandatory_linefeed();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// flush scheduled outputs
|
|
Packit Service |
7770af |
// maybe omit semicolon if possible
|
|
Packit Service |
7770af |
inspect.finalize(wbuf.buffer.size() == 0);
|
|
Packit Service |
7770af |
// prepend buffer on top
|
|
Packit Service |
7770af |
prepend_output(inspect.output());
|
|
Packit Service |
7770af |
// make sure we end with a linefeed
|
|
Packit Service |
7770af |
if (!ends_with(wbuf.buffer, opt.linefeed)) {
|
|
Packit Service |
7770af |
// if the output is not completely empty
|
|
Packit Service |
7770af |
if (!wbuf.buffer.empty()) append_string(opt.linefeed);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// search for unicode char
|
|
Packit Service |
7770af |
for(const char& chr : wbuf.buffer) {
|
|
Packit Service |
7770af |
// skip all ascii chars
|
|
Packit Service |
7770af |
// static cast to unsigned to handle `char` being signed / unsigned
|
|
Packit Service |
7770af |
if (static_cast<unsigned>(chr) < 128) continue;
|
|
Packit Service |
7770af |
// declare the charset
|
|
Packit Service |
7770af |
if (output_style() != COMPRESSED)
|
|
Packit Service |
7770af |
charset = "@charset \"UTF-8\";"
|
|
Packit Service |
7770af |
+ std::string(opt.linefeed);
|
|
Packit Service |
7770af |
else charset = "\xEF\xBB\xBF";
|
|
Packit Service |
7770af |
// abort search
|
|
Packit Service |
7770af |
break;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// add charset as first line, before comments and imports
|
|
Packit Service |
7770af |
if (!charset.empty()) prepend_string(charset);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
return wbuf;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(Comment_Ptr c)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
std::string txt = c->text()->to_string(opt);
|
|
Packit Service |
7770af |
// if (indentation && txt == "/**/") return;
|
|
Packit Service |
7770af |
bool important = c->is_important();
|
|
Packit Service |
7770af |
if (output_style() != COMPRESSED || important) {
|
|
Packit Service |
7770af |
if (buffer().size() == 0) {
|
|
Packit Service |
7770af |
top_nodes.push_back(c);
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
in_comment = true;
|
|
Packit Service |
7770af |
append_indentation();
|
|
Packit Service |
7770af |
c->text()->perform(this);
|
|
Packit Service |
7770af |
in_comment = false;
|
|
Packit Service |
7770af |
if (indentation == 0) {
|
|
Packit Service |
7770af |
append_mandatory_linefeed();
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
append_optional_linefeed();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(Ruleset_Ptr r)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Selector_Obj s = r->selector();
|
|
Packit Service |
7770af |
Block_Obj b = r->block();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Filter out rulesets that aren't printable (process its children though)
|
|
Packit Service |
7770af |
if (!Util::isPrintable(r, output_style())) {
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
const Statement_Obj& stm = b->at(i);
|
|
Packit Service |
7770af |
if (Cast<Has_Block>(stm)) {
|
|
Packit Service |
7770af |
if (!Cast<Declaration>(stm)) {
|
|
Packit Service |
7770af |
stm->perform(this);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
return;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (output_style() == NESTED) indentation += r->tabs();
|
|
Packit Service |
7770af |
if (opt.source_comments) {
|
|
Packit Service |
7770af |
std::stringstream ss;
|
|
Packit Service |
7770af |
append_indentation();
|
|
Packit Service |
7770af |
std::string path(File::abs2rel(r->pstate().path));
|
|
Packit Service |
7770af |
ss << "/* line " << r->pstate().line + 1 << ", " << path << " */";
|
|
Packit Service |
7770af |
append_string(ss.str());
|
|
Packit Service |
7770af |
append_optional_linefeed();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (s) s->perform(this);
|
|
Packit Service |
7770af |
append_scope_opener(b);
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Statement_Obj stm = b->at(i);
|
|
Packit Service |
7770af |
bool bPrintExpression = true;
|
|
Packit Service |
7770af |
// Check print conditions
|
|
Packit Service |
7770af |
if (Declaration_Ptr dec = Cast<Declaration>(stm)) {
|
|
Packit Service |
7770af |
if (String_Constant_Ptr valConst = Cast<String_Constant>(dec->value())) {
|
|
Packit Service |
7770af |
std::string val(valConst->value());
|
|
Packit Service |
7770af |
if (String_Quoted_Ptr qstr = Cast<String_Quoted>(valConst)) {
|
|
Packit Service |
7770af |
if (!qstr->quote_mark() && val.empty()) {
|
|
Packit Service |
7770af |
bPrintExpression = false;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else if (List_Ptr list = Cast<List>(dec->value())) {
|
|
Packit Service |
7770af |
bool all_invisible = true;
|
|
Packit Service |
7770af |
for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
|
|
Packit Service |
7770af |
Expression_Ptr item = list->at(list_i);
|
|
Packit Service |
7770af |
if (!item->is_invisible()) all_invisible = false;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (all_invisible) bPrintExpression = false;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// Print if OK
|
|
Packit Service |
7770af |
if (bPrintExpression) {
|
|
Packit Service |
7770af |
stm->perform(this);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (output_style() == NESTED) indentation -= r->tabs();
|
|
Packit Service |
7770af |
append_scope_closer(b);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
void Output::operator()(Keyframe_Rule_Ptr r)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Block_Obj b = r->block();
|
|
Packit Service |
7770af |
Selector_Obj v = r->name();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (!v.isNull()) {
|
|
Packit Service |
7770af |
v->perform(this);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (!b) {
|
|
Packit Service |
7770af |
append_colon_separator();
|
|
Packit Service |
7770af |
return;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
append_scope_opener();
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Statement_Obj stm = b->at(i);
|
|
Packit Service |
7770af |
stm->perform(this);
|
|
Packit Service |
7770af |
if (i < L - 1) append_special_linefeed();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
append_scope_closer();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(Supports_Block_Ptr f)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (f->is_invisible()) return;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Supports_Condition_Obj c = f->condition();
|
|
Packit Service |
7770af |
Block_Obj b = f->block();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Filter out feature blocks that aren't printable (process its children though)
|
|
Packit Service |
7770af |
if (!Util::isPrintable(f, output_style())) {
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Statement_Obj stm = b->at(i);
|
|
Packit Service |
7770af |
if (Cast<Has_Block>(stm)) {
|
|
Packit Service |
7770af |
stm->perform(this);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
return;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (output_style() == NESTED) indentation += f->tabs();
|
|
Packit Service |
7770af |
append_indentation();
|
|
Packit Service |
7770af |
append_token("@supports", f);
|
|
Packit Service |
7770af |
append_mandatory_space();
|
|
Packit Service |
7770af |
c->perform(this);
|
|
Packit Service |
7770af |
append_scope_opener();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Statement_Obj stm = b->at(i);
|
|
Packit Service |
7770af |
stm->perform(this);
|
|
Packit Service |
7770af |
if (i < L - 1) append_special_linefeed();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (output_style() == NESTED) indentation -= f->tabs();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
append_scope_closer();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(Media_Block_Ptr m)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (m->is_invisible()) return;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Block_Obj b = m->block();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Filter out media blocks that aren't printable (process its children though)
|
|
Packit Service |
7770af |
if (!Util::isPrintable(m, output_style())) {
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Statement_Obj stm = b->at(i);
|
|
Packit Service |
7770af |
if (Cast<Has_Block>(stm)) {
|
|
Packit Service |
7770af |
stm->perform(this);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
return;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (output_style() == NESTED) indentation += m->tabs();
|
|
Packit Service |
7770af |
append_indentation();
|
|
Packit Service |
7770af |
append_token("@media", m);
|
|
Packit Service |
7770af |
append_mandatory_space();
|
|
Packit Service |
7770af |
in_media_block = true;
|
|
Packit Service |
7770af |
m->media_queries()->perform(this);
|
|
Packit Service |
7770af |
in_media_block = false;
|
|
Packit Service |
7770af |
append_scope_opener();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
if (b->at(i)) {
|
|
Packit Service |
7770af |
Statement_Obj stm = b->at(i);
|
|
Packit Service |
7770af |
stm->perform(this);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (i < L - 1) append_special_linefeed();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (output_style() == NESTED) indentation -= m->tabs();
|
|
Packit Service |
7770af |
append_scope_closer();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(Directive_Ptr a)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
std::string kwd = a->keyword();
|
|
Packit Service |
7770af |
Selector_Obj s = a->selector();
|
|
Packit Service |
7770af |
Expression_Obj v = a->value();
|
|
Packit Service |
7770af |
Block_Obj b = a->block();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
append_indentation();
|
|
Packit Service |
7770af |
append_token(kwd, a);
|
|
Packit Service |
7770af |
if (s) {
|
|
Packit Service |
7770af |
append_mandatory_space();
|
|
Packit Service |
7770af |
in_wrapped = true;
|
|
Packit Service |
7770af |
s->perform(this);
|
|
Packit Service |
7770af |
in_wrapped = false;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (v) {
|
|
Packit Service |
7770af |
append_mandatory_space();
|
|
Packit Service |
7770af |
// ruby sass bug? should use options?
|
|
Packit Service |
7770af |
append_token(v->to_string(/* opt */), v);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (!b) {
|
|
Packit Service |
7770af |
append_delimiter();
|
|
Packit Service |
7770af |
return;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (b->is_invisible() || b->length() == 0) {
|
|
Packit Service |
7770af |
append_optional_space();
|
|
Packit Service |
7770af |
return append_string("{}");
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
append_scope_opener();
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
bool format = kwd != "@font-face";;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
Packit Service |
7770af |
Statement_Obj stm = b->at(i);
|
|
Packit Service |
7770af |
stm->perform(this);
|
|
Packit Service |
7770af |
if (i < L - 1 && format) append_special_linefeed();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
append_scope_closer();
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(String_Quoted_Ptr s)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
if (s->quote_mark()) {
|
|
Packit Service |
7770af |
append_token(quote(s->value(), s->quote_mark()), s);
|
|
Packit Service |
7770af |
} else if (!in_comment) {
|
|
Packit Service |
7770af |
append_token(string_to_output(s->value()), s);
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
append_token(s->value(), s);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
void Output::operator()(String_Constant_Ptr s)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
std::string value(s->value());
|
|
Packit Service |
7770af |
if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
|
|
Packit Service |
7770af |
value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
if (!in_comment) {
|
|
Packit Service |
7770af |
append_token(string_to_output(value), s);
|
|
Packit Service |
7770af |
} else {
|
|
Packit Service |
7770af |
append_token(value, s);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|