From 40693d54a5d9f9f5f53b594863240d2f686b1727 Mon Sep 17 00:00:00 2001 From: xzyfer Date: Tue, 4 Nov 2014 12:25:04 +1100 Subject: [PATCH] Hoist feature query's selector --- ast.hpp | 3 +- expand.cpp | 1 + extend.cpp | 4 +++ output_nested.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++--- output_nested.hpp | 1 + util.cpp | 5 +-- 6 files changed, 92 insertions(+), 8 deletions(-) diff --git a/ast.hpp b/ast.hpp index c8ed997b44..a249520a8c 100644 --- a/ast.hpp +++ b/ast.hpp @@ -345,9 +345,10 @@ namespace Sass { /////////////////// class Feature_Block : public Has_Block { ADD_PROPERTY(Feature_Queries*, feature_queries); + ADD_PROPERTY(Selector*, selector); public: Feature_Block(string path, Position position, Feature_Queries* fqs, Block* b) - : Has_Block(path, position, b), feature_queries_(fqs) + : Has_Block(path, position, b), feature_queries_(fqs), selector_(0) { } bool is_hoistable() { return true; } ATTACH_OPERATIONS(); diff --git a/expand.cpp b/expand.cpp index 4bde1b762d..95eafc2e4c 100644 --- a/expand.cpp +++ b/expand.cpp @@ -95,6 +95,7 @@ namespace Sass { f->position(), static_cast(feature_queries), f->block()->perform(this)->block()); + ff->selector(selector_stack.back()); return ff; } diff --git a/extend.cpp b/extend.cpp index 7f3ddfdf5f..233f135c0b 100644 --- a/extend.cpp +++ b/extend.cpp @@ -1939,6 +1939,10 @@ namespace Sass { void Extend::operator()(Feature_Block* pFeatureBlock) { + if (pFeatureBlock->selector()) { + extendObjectWithSelectorAndBlock(pFeatureBlock, ctx, subset_map); + } + pFeatureBlock->block()->perform(this); } diff --git a/output_nested.cpp b/output_nested.cpp index 7ca38dc5ea..4d631602cc 100644 --- a/output_nested.cpp +++ b/output_nested.cpp @@ -124,6 +124,82 @@ namespace Sass { } } + void Output_Nested::operator()(Feature_Block* f) + { + Feature_Queries* q = f->feature_queries(); + Block* b = f->block(); + + // Filter out feature blocks that aren't printable (process its children though) + if (!Util::isPrintable(f)) { + for (size_t i = 0, L = b->length(); i < L; ++i) { + Statement* stm = (*b)[i]; + if (dynamic_cast(stm)) { + stm->perform(this); + } + } + return; + } + + indent(); + ctx->source_map.add_mapping(f); + append_to_buffer("@supports "); + q->perform(this); + append_to_buffer(" {\n"); + + Selector* e = f->selector(); + if (e && b->has_non_hoistable()) { + // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable + ++indentation; + indent(); + e->perform(this); + append_to_buffer(" {\n"); + + ++indentation; + for (size_t i = 0, L = b->length(); i < L; ++i) { + Statement* stm = (*b)[i]; + if (!stm->is_hoistable()) { + if (!stm->block()) indent(); + stm->perform(this); + append_to_buffer("\n"); + } + } + --indentation; + + buffer.erase(buffer.length()-1); + if (ctx) ctx->source_map.remove_line(); + append_to_buffer(" }\n"); + --indentation; + + ++indentation; + ++indentation; + for (size_t i = 0, L = b->length(); i < L; ++i) { + Statement* stm = (*b)[i]; + if (stm->is_hoistable()) { + stm->perform(this); + } + } + --indentation; + --indentation; + } + else { + // JMA - not hoisted, just output in order + ++indentation; + for (size_t i = 0, L = b->length(); i < L; ++i) { + Statement* stm = (*b)[i]; + if (!stm->is_hoistable()) { + if (!stm->block()) indent(); + } + stm->perform(this); + append_to_buffer("\n"); + } + --indentation; + } + + buffer.erase(buffer.length()-1); + if (ctx) ctx->source_map.remove_line(); + append_to_buffer(" }\n"); + } + void Output_Nested::operator()(Media_Block* m) { List* q = m->media_queries(); @@ -139,7 +215,7 @@ namespace Sass { } return; } - + indent(); ctx->source_map.add_mapping(m); append_to_buffer("@media "); @@ -153,7 +229,7 @@ namespace Sass { indent(); e->perform(this); append_to_buffer(" {\n"); - + ++indentation; for (size_t i = 0, L = b->length(); i < L; ++i) { Statement* stm = (*b)[i]; @@ -164,12 +240,12 @@ namespace Sass { } } --indentation; - + buffer.erase(buffer.length()-1); if (ctx) ctx->source_map.remove_line(); append_to_buffer(" }\n"); --indentation; - + ++indentation; ++indentation; for (size_t i = 0, L = b->length(); i < L; ++i) { @@ -194,7 +270,7 @@ namespace Sass { } --indentation; } - + buffer.erase(buffer.length()-1); if (ctx) ctx->source_map.remove_line(); append_to_buffer(" }\n"); diff --git a/output_nested.hpp b/output_nested.hpp index 6e62461e6b..20e24b6106 100644 --- a/output_nested.hpp +++ b/output_nested.hpp @@ -43,6 +43,7 @@ namespace Sass { virtual void operator()(Block*); virtual void operator()(Ruleset*); // virtual void operator()(Propset*); + virtual void operator()(Feature_Block*); virtual void operator()(Media_Block*); virtual void operator()(At_Rule*); // virtual void operator()(Declaration*); diff --git a/util.cpp b/util.cpp index 144c735156..b8d75fb954 100644 --- a/util.cpp +++ b/util.cpp @@ -55,12 +55,13 @@ namespace Sass { Block* b = f->block(); - bool hasSelectors = false; + bool hasSelectors = f->selector() && static_cast(f->selector())->length() > 0; + bool hasDeclarations = false; bool hasPrintableChildBlocks = false; for (size_t i = 0, L = b->length(); i < L; ++i) { Statement* stm = (*b)[i]; - if (!stm->is_hoistable() && !hasSelectors) { + if (!stm->is_hoistable() && f->selector() != NULL && !hasSelectors) { // If a statement isn't hoistable, the selectors apply to it. If there are no selectors (a selector list of length 0), // then those statements aren't considered printable. That means there was a placeholder that was removed. If the selector // is NULL, then that means there was never a wrapping selector and it is printable (think of a top level media block with