Skip to content

Commit

Permalink
Improve custom importer to pass parent import context
Browse files Browse the repository at this point in the history
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!
  • Loading branch information
mgreter committed Dec 6, 2014
1 parent 0877bf0 commit 34a5752
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 21 deletions.
26 changes: 22 additions & 4 deletions context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<AST_Node>()),
source_c_str (initializers.source_c_str()),
sources (vector<const char*>()),
include_paths (initializers.include_paths()),
queue (vector<pair<string, const char*> >()),
queue (vector<Sass_Queued>()),
style_sheets (map<string, Block*>()),
source_map (resolve_relative_path(initializers.output_path(), initializers.source_map_file(), get_cwd())),
c_functions (vector<Sass_C_Function_Callback>()),
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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(), "");
Expand Down
11 changes: 10 additions & 1 deletion context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<AST_Node> mem;

Expand All @@ -57,7 +65,7 @@ namespace Sass {
// vectors above have same size

vector<string> include_paths; // lookup paths for includes
vector<pair<string, const char*> > queue; // queue of files to be parsed
vector<Sass_Queued> queue; // queue of files to be parsed
map<string, Block*> style_sheets; // map of paths to ASTs
SourceMap source_map;
vector<Sass_C_Function_Callback> c_functions;
Expand All @@ -75,6 +83,7 @@ namespace Sass {

// overload import calls
Sass_C_Import_Callback importer;
vector<struct Sass_Import*> import_stack;

map<string, Color*> names_to_colors;
map<int, string> colors_to_names;
Expand Down
23 changes: 14 additions & 9 deletions parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "prelexer.hpp"
#endif

#include "sass_functions.h"

#include <typeinfo>

namespace Sass {
Expand Down Expand Up @@ -158,36 +160,39 @@ 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;
const char *file = sass_import_get_path(include);
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
}
Expand Down
26 changes: 21 additions & 5 deletions sass_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern "C" {
// External import entry
struct Sass_Import {
char* path;
char* base;
char* source;
char* srcmap;
};
Expand Down Expand Up @@ -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]; }
Expand All @@ -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; }

Expand Down
11 changes: 9 additions & 2 deletions sass_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 34a5752

Please sign in to comment.