From 34a5752bcaad6c401c641897f352ca7c59f4c252 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Fri, 5 Dec 2014 05:21:07 +0100 Subject: [PATCH] Improve custom importer to pass parent import context One example would be a custom importer that loads the content from the web. If this includes another import, it should be loaded relative to the parent file. To do this, the custom importer needs to know the context of the parent import. Which is what this commit will fix! --- context.cpp | 26 ++++++++++++++++++++++---- context.hpp | 11 ++++++++++- parser.cpp | 23 ++++++++++++++--------- sass_functions.cpp | 26 +++++++++++++++++++++----- sass_functions.h | 11 +++++++++-- 5 files changed, 76 insertions(+), 21 deletions(-) diff --git a/context.cpp b/context.cpp index 44d23e346d..e2a8c335e7 100644 --- a/context.cpp +++ b/context.cpp @@ -44,12 +44,20 @@ namespace Sass { using std::cerr; using std::endl; + Sass_Queued::Sass_Queued(const string& load_path, const string& abs_path, const char* source) + { + this->load_path = load_path; + this->abs_path = abs_path; + this->source = source; + } + + Context::Context(Context::Data initializers) : mem(Memory_Manager()), source_c_str (initializers.source_c_str()), sources (vector()), include_paths (initializers.include_paths()), - queue (vector >()), + queue (vector()), style_sheets (map()), source_map (resolve_relative_path(initializers.output_path(), initializers.source_map_file(), get_cwd())), c_functions (vector()), @@ -96,6 +104,8 @@ namespace Sass { { // everything that gets put into sources will be freed by us for (size_t i = 0; i < sources.size(); ++i) delete[] sources[i]; + for (size_t n = 0; n < import_stack.size(); ++n) sass_delete_import(import_stack[n]); + sources.clear(); import_stack.clear(); } void Context::setup_color_map() @@ -155,7 +165,7 @@ namespace Sass { { sources.push_back(contents); included_files.push_back(abs_path); - queue.push_back(make_pair(load_path, contents)); + queue.push_back(Sass_Queued(load_path, abs_path, contents)); source_map.source_index.push_back(sources.size() - 1); include_links.push_back(resolve_relative_path(abs_path, source_map_file, cwd)); } @@ -246,10 +256,18 @@ namespace Sass { { Block* root = 0; for (size_t i = 0; i < queue.size(); ++i) { - Parser p(Parser::from_c_str(queue[i].second, *this, queue[i].first, Position(1 + i, 1, 1))); + struct Sass_Import* import = sass_make_import( + queue[i].load_path.c_str(), + queue[i].abs_path.c_str(), + 0, 0 + ); + import_stack.push_back(import); + Parser p(Parser::from_c_str(queue[i].source, *this, queue[i].load_path, Position(1 + i, 1, 1))); Block* ast = p.parse(); + sass_delete_import(import_stack.back()); + import_stack.pop_back(); if (i == 0) root = ast; - style_sheets[queue[i].first] = ast; + style_sheets[queue[i].load_path] = ast; } Env tge; Backtrace backtrace(0, "", Position(), ""); diff --git a/context.hpp b/context.hpp index 8bffb87cdb..04eb35b19c 100644 --- a/context.hpp +++ b/context.hpp @@ -42,6 +42,14 @@ namespace Sass { enum Output_Style { NESTED, EXPANDED, COMPACT, COMPRESSED, FORMATTED }; + struct Sass_Queued { + string abs_path; + string load_path; + const char* source; + public: + Sass_Queued(const string& load_path, const string& abs_path, const char* source); + }; + struct Context { Memory_Manager mem; @@ -57,7 +65,7 @@ namespace Sass { // vectors above have same size vector include_paths; // lookup paths for includes - vector > queue; // queue of files to be parsed + vector queue; // queue of files to be parsed map style_sheets; // map of paths to ASTs SourceMap source_map; vector c_functions; @@ -75,6 +83,7 @@ namespace Sass { // overload import calls Sass_C_Import_Callback importer; + vector import_stack; map names_to_colors; map colors_to_names; diff --git a/parser.cpp b/parser.cpp index 98c9d3191c..a6f6e958d4 100644 --- a/parser.cpp +++ b/parser.cpp @@ -12,6 +12,8 @@ #include "prelexer.hpp" #endif +#include "sass_functions.h" + #include namespace Sass { @@ -158,11 +160,15 @@ namespace Sass { Sass_C_Import_Callback importer = ctx.importer; // custom importer if (importer) { + Sass_Import* current = ctx.import_stack.back(); 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; + // create a new import entry + string inc_path = unquote(import_path); + struct Sass_Import** includes = fn( + inc_path.c_str(), + sass_import_get_path(current), + cookie); if (includes) { while (*includes) { struct Sass_Import* include = *includes; @@ -170,24 +176,23 @@ namespace Sass { char *source = sass_import_take_source(include); // char *srcmap = sass_import_take_srcmap(include); if (source) { - string inc_path = unquote(import_path); if (file) { - ctx.add_source(file, import_path, source); + ctx.add_source(file, inc_path, source); imp->files().push_back(file); } else { - ctx.add_source(import_path, import_path, source); - imp->files().push_back(import_path); + ctx.add_source(inc_path, inc_path, source); + imp->files().push_back(inc_path); } } else if(file) { add_single_file(imp, file); } ++includes; } - // deallocate returned memory - sass_delete_import_list(imports); // go for next parse loop continue; } + // deallocate returned memory + sass_delete_import_list(includes); // custom importer returned nothing // means we should use default loader } diff --git a/sass_functions.cpp b/sass_functions.cpp index a9d37ca689..4e279c4bd9 100644 --- a/sass_functions.cpp +++ b/sass_functions.cpp @@ -43,6 +43,7 @@ extern "C" { // External import entry struct Sass_Import { char* path; + char* base; char* source; char* srcmap; }; @@ -73,16 +74,23 @@ extern "C" { // Creator for a single import entry returned by the custom importer inside the list // We take ownership of the memory for source and srcmap (freed when context is destroyd) - struct Sass_Import* sass_make_import_entry(const char* path, char* source, char* srcmap) + struct Sass_Import* sass_make_import(const char* path, const char* base, char* source, char* srcmap) { Sass_Import* v = (Sass_Import*) calloc(1, sizeof(Sass_Import)); if (v == 0) return 0; v->path = strdup(path); + v->base = strdup(base); v->source = source; v->srcmap = srcmap; return v; } + // Older style, but somehow still valid - keep around or deprecate? + struct Sass_Import* sass_make_import_entry(const char* path, char* source, char* srcmap) + { + return sass_make_import(path, path, source, srcmap); + } + // Setters and getters for entries on the import list void sass_import_set_list_entry(struct Sass_Import** list, size_t idx, struct Sass_Import* entry) { list[idx] = entry; } struct Sass_Import* sass_import_get_list_entry(struct Sass_Import** list, size_t idx) { return list[idx]; } @@ -93,17 +101,25 @@ extern "C" { struct Sass_Import** it = list; if (list == 0) return; while(*list) { - free((*list)->path); - free((*list)->source); - free((*list)->srcmap); - free(*list); + sass_delete_import(*list); ++list; } free(it); } + // Just in case we have some stray import structs + void sass_delete_import(struct Sass_Import* import) + { + free(import->path); + free(import->base); + free(import->source); + free(import->srcmap); + free(import); + } + // Getter for import entry const char* sass_import_get_path(struct Sass_Import* entry) { return entry->path; } + const char* sass_import_get_base(struct Sass_Import* entry) { return entry->base; } const char* sass_import_get_source(struct Sass_Import* entry) { return entry->source; } const char* sass_import_get_srcmap(struct Sass_Import* entry) { return entry->srcmap; } diff --git a/sass_functions.h b/sass_functions.h index acf0561942..6a1404a6b4 100644 --- a/sass_functions.h +++ b/sass_functions.h @@ -9,13 +9,16 @@ extern "C" { #endif +// Forward declaration +struct Sass_Import; + // Forward declaration struct Sass_C_Import_Descriptor; // Typedef defining the custom importer callback typedef struct Sass_C_Import_Descriptor (*Sass_C_Import_Callback); // Typedef defining the importer c function prototype -typedef struct Sass_Import** (*Sass_C_Import_Fn) (const char* url, void* cookie); +typedef struct Sass_Import** (*Sass_C_Import_Fn) (const char* url, const char* prev, void* cookie); // Creators for custom importer callback (with some additional pointer) // The pointer is mostly used to store the callback into the actual binding @@ -30,6 +33,7 @@ void* sass_import_get_cookie (Sass_C_Import_Callback fn); struct Sass_Import** sass_make_import_list (size_t length); // Creator for a single import entry returned by the custom importer inside the list struct Sass_Import* sass_make_import_entry (const char* path, char* source, char* srcmap); +struct Sass_Import* sass_make_import (const char* path, const char* base, char* source, char* srcmap); // Setters to insert an entry into the import list (you may also use [] access directly) // Since we are dealing with pointers they should have a guaranteed and fixed size @@ -38,6 +42,7 @@ struct Sass_Import* sass_import_get_list_entry (struct Sass_Import** list, size_ // Getters for import entry const char* sass_import_get_path (struct Sass_Import*); +const char* sass_import_get_base (struct Sass_Import*); const char* sass_import_get_source (struct Sass_Import*); const char* sass_import_get_srcmap (struct Sass_Import*); // Explicit functions to take ownership of these items @@ -47,6 +52,8 @@ char* sass_import_take_srcmap (struct Sass_Import*); // Deallocator for associated memory (incl. entries) void sass_delete_import_list (struct Sass_Import**); +// Just in case we have some stray import structs +void sass_delete_import (struct Sass_Import*); // Forward declaration @@ -56,7 +63,7 @@ struct Sass_C_Function_Descriptor; typedef struct Sass_C_Function_Descriptor* (*Sass_C_Function_List); typedef struct Sass_C_Function_Descriptor (*Sass_C_Function_Callback); // Typedef defining custom function prototype and its return value type -typedef union Sass_Value*(*Sass_C_Function) (union Sass_Value*, void *cookie); +typedef union Sass_Value*(*Sass_C_Function) (union Sass_Value*, void* cookie); // Creators for sass function list and function descriptors