diff --git a/context.cpp b/context.cpp index 387df90e65..544b14a7e8 100644 --- a/context.cpp +++ b/context.cpp @@ -62,6 +62,7 @@ namespace Sass { source_map_contents (initializers.source_map_contents()), omit_source_map_url (initializers.omit_source_map_url()), is_indented_syntax_src (initializers.is_indented_syntax_src()), + importer (initializers.importer()), names_to_colors (map()), colors_to_names (map()), precision (initializers.precision()), diff --git a/context.hpp b/context.hpp index 35761b0ba6..9568294f57 100644 --- a/context.hpp +++ b/context.hpp @@ -72,6 +72,9 @@ namespace Sass { bool omit_source_map_url; // disable source map comment in css output bool is_indented_syntax_src; // treat source string as sass + // overload import calls + Sass_C_Import_Callback importer; + map names_to_colors; map colors_to_names; @@ -95,6 +98,7 @@ namespace Sass { KWD_ARG(Data, bool, _skip_source_map_update); KWD_ARG(Data, bool, source_map_embed); KWD_ARG(Data, bool, source_map_contents); + KWD_ARG(Data, Sass_C_Import_Callback, importer); }; Context(Data); diff --git a/parser.cpp b/parser.cpp index f3825de8c6..3ee5d2a39c 100644 --- a/parser.cpp +++ b/parser.cpp @@ -119,6 +119,32 @@ namespace Sass { return root; } + void Parser::add_single_file (Import* imp, string import_path) { + + string extension; + string unquoted(unquote(import_path)); + if (unquoted.length() > 4) { // 2 quote marks + the 4 chars in .css + // a string constant is guaranteed to end with a quote mark, so make sure to skip it when indexing from the end + extension = unquoted.substr(unquoted.length() - 4, 4); + } + + if (extension == ".css") { + String_Constant* loc = new (ctx.mem) String_Constant(path, source_position, import_path, true); + Argument* loc_arg = new (ctx.mem) Argument(path, source_position, loc); + Arguments* loc_args = new (ctx.mem) Arguments(path, source_position); + (*loc_args) << loc_arg; + Function_Call* new_url = new (ctx.mem) Function_Call(path, source_position, "url", loc_args); + imp->urls().push_back(new_url); + } + else { + string current_dir = File::dir_name(path); + string resolved(ctx.add_file(current_dir, unquoted)); + if (resolved.empty()) error("file to import not found or unreadable: " + unquoted + "\nCurrent dir: " + current_dir); + imp->files().push_back(resolved); + } + + } + Import* Parser::parse_import() { lex< import >(); @@ -127,25 +153,47 @@ namespace Sass { do { if (lex< string_constant >()) { string import_path(lexed); - string extension; - if (import_path.length() > 6) { // 2 quote marks + the 4 chars in .css - // a string constant is guaranteed to end with a quote mark, so make sure to skip it when indexing from the end - extension = import_path.substr(import_path.length() - 5, 4); - } - if (extension == ".css") { - String_Constant* loc = new (ctx.mem) String_Constant(path, source_position, import_path, true); - Argument* loc_arg = new (ctx.mem) Argument(path, source_position, loc); - Arguments* loc_args = new (ctx.mem) Arguments(path, source_position); - (*loc_args) << loc_arg; - Function_Call* new_url = new (ctx.mem) Function_Call(path, source_position, "url", loc_args); - imp->urls().push_back(new_url); - } - else { - string current_dir = File::dir_name(path); - string resolved(ctx.add_file(current_dir, unquote(import_path))); - if (resolved.empty()) error("file to import not found or unreadable: " + import_path + "\nCurrent dir: " + current_dir); - imp->files().push_back(resolved); + + // struct Sass_Options opt = sass_context_get_options(ctx) + Sass_C_Import_Callback importer = ctx.importer; + // custom importer + if (importer) { + Sass_C_Import_Fn fn = sass_import_get_function(importer); + void* cookie = sass_import_get_cookie(importer); + // get null delimited "array" of "external" imports + struct Sass_Import** imports = fn(import_path.c_str(), cookie); + struct Sass_Import** includes = imports; + if (includes) { + while (*includes) { + struct Sass_Import* include = *includes; + const char *file = sass_import_get_path(include); + const char *source = sass_import_get_source(include); + // const char *srcmap = sass_import_get_srcmap[include]; + if (source) { + string inc_path = unquote(import_path); + if (file) { + ctx.add_source(file, import_path, strdup(source)); + imp->files().push_back(file); + } else { + ctx.add_source(import_path, import_path, strdup(source)); + imp->files().push_back(import_path); + } + } else if(file) { + add_single_file(imp, file); + } + ++includes; + } + // deallocate returned memory + sass_delete_import_list(imports); + // go for next parse loop + continue; + } + // custom importer returned nothing + // means we should use default loader } + + add_single_file(imp, import_path); + } else if (peek< uri_prefix >()) { imp->urls().push_back(parse_value()); diff --git a/parser.hpp b/parser.hpp index c0f0205b07..ea3d682f9f 100644 --- a/parser.hpp +++ b/parser.hpp @@ -37,6 +37,8 @@ namespace Sass { using namespace Prelexer; class Parser { + private: + void add_single_file (Import* imp, string import_path); public: class AST_Node; diff --git a/sass_context.cpp b/sass_context.cpp index c49b1baa42..5659ea673d 100644 --- a/sass_context.cpp +++ b/sass_context.cpp @@ -85,6 +85,9 @@ extern "C" { // Custom functions that can be called from sccs code Sass_C_Function_List c_functions; + // Custom functions to overload imports + Sass_C_Import_Callback importer; + }; // base for all contexts @@ -214,6 +217,7 @@ extern "C" { .omit_source_map_url(c_ctx->omit_source_map_url) .image_path(safe_str(c_ctx->image_path)) .include_paths_c_str(c_ctx->include_path) + .importer(c_ctx->importer) .include_paths_array(include_paths) .include_paths(vector()) .precision(c_ctx->precision ? c_ctx->precision : 5); @@ -423,6 +427,7 @@ extern "C" { IMPLEMENT_SASS_OPTION_SETTER(const char*, include_path); IMPLEMENT_SASS_OPTION_SETTER(const char*, source_map_file); IMPLEMENT_SASS_OPTION_SETTER(Sass_C_Function_List, c_functions); + IMPLEMENT_SASS_OPTION_SETTER(Sass_C_Import_Callback, importer); // Create getter and setters for context IMPLEMENT_SASS_CONTEXT_GETTER(int, error_status); diff --git a/sass_context.h b/sass_context.h index 1f5f9e517b..79bde0bab2 100644 --- a/sass_context.h +++ b/sass_context.h @@ -67,6 +67,8 @@ void sass_option_set_include_path (struct Sass_Options* options, const char* inc void sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file); // Sass_C_Function_List sass_option_get_c_functions (struct Sass_Options* options); void sass_option_set_c_functions (struct Sass_Options* options, Sass_C_Function_List c_functions); +// Sass_C_Import_Callback sass_option_get_importer (struct Sass_Options* options); +void sass_option_set_importer (struct Sass_Options* options, Sass_C_Import_Callback importer); // Getter functions for context const char* sass_context_get_output_string (struct Sass_Context* ctx);