Skip to content

Commit 4a522c3

Browse files
committed
Add support for multiple importers
Call them in priority order so each one can decide if it wants to handle a certain url. Return `null` to skip an importer and to check the next one. Continue until one returns a valid import. Otherwise libsass will handle it.
1 parent ea57348 commit 4a522c3

15 files changed

+166
-97
lines changed

context.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ namespace Sass {
5050
this->source = source;
5151
}
5252

53+
inline bool sort_importers (const Sass_C_Importer_Call& i, const Sass_C_Importer_Call& j)
54+
{ return sass_importer_get_priority(i) < sass_importer_get_priority(j); }
5355

5456
Context::Context(Context::Data initializers)
5557
: // Output(this),
@@ -61,7 +63,8 @@ namespace Sass {
6163
queue (vector<Sass_Queued>()),
6264
style_sheets (map<string, Block*>()),
6365
emitter (this),
64-
c_functions (vector<Sass_C_Function_Callback>()),
66+
c_functions (vector<Sass_C_Function_Call>()),
67+
c_importers (vector<Sass_C_Importer_Call>()),
6568
indent (initializers.indent()),
6669
linefeed (initializers.linefeed()),
6770
input_path (make_canonical_path(initializers.input_path())),
@@ -74,7 +77,6 @@ namespace Sass {
7477
source_map_contents (initializers.source_map_contents()),
7578
omit_source_map_url (initializers.omit_source_map_url()),
7679
is_indented_syntax_src (initializers.is_indented_syntax_src()),
77-
importer (initializers.importer()),
7880
names_to_colors (map<string, Color*>()),
7981
colors_to_names (map<int, string>()),
8082
precision (initializers.precision()),
@@ -104,7 +106,11 @@ namespace Sass {
104106
for(auto fn : plugins.get_functions()) {
105107
c_functions.push_back(fn);
106108
}
109+
for(auto fn : plugins.get_importers()) {
110+
c_importers.push_back(fn);
111+
}
107112

113+
sort (c_importers.begin(), c_importers.end(), sort_importers);
108114
string entry_point = initializers.entry_point();
109115
if (!entry_point.empty()) {
110116
string result(add_file(entry_point));
@@ -117,6 +123,17 @@ namespace Sass {
117123

118124
}
119125

126+
void Context::add_c_function(Sass_C_Function_Call function)
127+
{
128+
c_functions.push_back(function);
129+
}
130+
void Context::add_c_importer(Sass_C_Importer_Call importer)
131+
{
132+
c_importers.push_back(importer);
133+
// need to sort the array afterwards (no big deal)
134+
sort (c_importers.begin(), c_importers.end(), sort_importers);
135+
}
136+
120137
Context::~Context()
121138
{
122139
// everything that gets put into sources will be freed by us
@@ -263,7 +280,7 @@ namespace Sass {
263280
void register_overload_stub(Context&, string name, Env* env);
264281
void register_built_in_functions(Context&, Env* env);
265282
void register_c_functions(Context&, Env* env, Sass_C_Function_List);
266-
void register_c_function(Context&, Env* env, Sass_C_Function_Callback);
283+
void register_c_function(Context&, Env* env, Sass_C_Function_Call);
267284

268285
char* Context::compile_block(Block* root)
269286
{
@@ -515,7 +532,7 @@ namespace Sass {
515532
++descrs;
516533
}
517534
}
518-
void register_c_function(Context& ctx, Env* env, Sass_C_Function_Callback descr)
535+
void register_c_function(Context& ctx, Env* env, Sass_C_Function_Call descr)
519536
{
520537
Definition* def = make_c_function(
521538
sass_function_get_signature(descr),

context.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ namespace Sass {
5151
map<string, Block*> style_sheets; // map of paths to ASTs
5252
// SourceMap source_map;
5353
Output emitter;
54-
vector<Sass_C_Function_Callback> c_functions;
54+
55+
vector<Sass_C_Function_Call> c_functions;
56+
vector<Sass_C_Importer_Call> c_importers;
57+
58+
void add_c_function(Sass_C_Function_Call function);
59+
void add_c_importer(Sass_C_Importer_Call importer);
5560

5661
string indent; // String to be used for indentation
5762
string linefeed; // String to be used for line feeds
@@ -67,7 +72,6 @@ namespace Sass {
6772
bool is_indented_syntax_src; // treat source string as sass
6873

6974
// overload import calls
70-
Sass_C_Import_Callback importer;
7175
vector<struct Sass_Import*> import_stack;
7276

7377
map<string, Color*> names_to_colors;
@@ -97,7 +101,6 @@ namespace Sass {
97101
KWD_ARG(Data, size_t, precision);
98102
KWD_ARG(Data, bool, source_map_embed);
99103
KWD_ARG(Data, bool, source_map_contents);
100-
KWD_ARG(Data, Sass_C_Import_Callback, importer);
101104
};
102105

103106
Context(Data);

contrib/plugin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ extern "C" const char* ADDCALL libsass_get_version() {
1919
extern "C" Sass_C_Function_List ADDCALL libsass_load_functions()
2020
{
2121
// allocate a custom function caller
22-
Sass_C_Function_Callback fn_foo =
22+
Sass_C_Function_Call fn_foo =
2323
sass_make_function("foo()", call_fn_foo, (void*)42);
2424
// create list of all custom functions
2525
Sass_C_Function_List fn_list = sass_make_function_list(1);

file.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ namespace Sass {
5757
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
5858
(!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)));
5959
#else
60-
struct stat buffer;
61-
return (stat (path.c_str(), &buffer) == 0);
60+
struct stat st_buf;
61+
return (stat (path.c_str(), &st_buf) == 0) &&
62+
(!S_ISDIR (st_buf.st_mode));
6263
#endif
6364
}
6465

@@ -284,7 +285,7 @@ namespace Sass {
284285
{
285286
if (paths == 0) return string("");
286287
vector<string> includes(0);
287-
includes.push_back(".");
288+
// includes.push_back(".");
288289
const char** it = paths;
289290
while (it && *it) {
290291
includes.push_back(*it);

parser.cpp

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,20 @@ namespace Sass {
178178

179179
}
180180

181+
void Parser::import_single_file (Import* imp, string import_path) {
182+
183+
if (!unquote(import_path).substr(0, 7).compare("http://") ||
184+
!unquote(import_path).substr(0, 8).compare("https://") ||
185+
!unquote(import_path).substr(0, 2).compare("//"))
186+
{
187+
imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
188+
}
189+
else {
190+
add_single_file(imp, import_path);
191+
}
192+
193+
}
194+
181195
Import* Parser::parse_import()
182196
{
183197
lex< kwd_import >();
@@ -187,21 +201,18 @@ namespace Sass {
187201
while (lex< block_comment >());
188202
if (lex< quoted_string >()) {
189203
string import_path(lexed);
190-
191-
// struct Sass_Options opt = sass_context_get_options(ctx)
192-
Sass_C_Import_Callback importer = ctx.importer;
193-
// custom importer
194-
if (importer) {
195-
Sass_Import* current = ctx.import_stack.back();
196-
Sass_C_Import_Fn fn = sass_import_get_function(importer);
197-
void* cookie = sass_import_get_cookie(importer);
198-
// create a new import entry
199-
string inc_path = unquote(import_path);
200-
struct Sass_Import** includes = fn(
201-
inc_path.c_str(),
202-
sass_import_get_path(current),
203-
cookie);
204-
if (includes) {
204+
bool has_custom_import = false;
205+
Sass_Import* current = ctx.import_stack.back();
206+
const char* cur_path = sass_import_get_path(current);
207+
string load_path = unquote(import_path);
208+
for (auto importer : ctx.c_importers) {
209+
if (has_custom_import) break;
210+
Sass_C_Importer fn = sass_importer_get_function(importer);
211+
// int priority = sass_importer_get_priority(importer);
212+
void* cookie = sass_importer_get_cookie(importer);
213+
if (struct Sass_Import** includes =
214+
fn(load_path.c_str(), cur_path, cookie)
215+
) {
205216
struct Sass_Import** list = includes;
206217
while (*includes) {
207218
struct Sass_Import* include = *includes;
@@ -210,38 +221,32 @@ namespace Sass {
210221
size_t line = sass_import_get_error_line(include);
211222
size_t column = sass_import_get_error_column(include);
212223
const char* message = sass_import_get_error_message(include);
213-
// char *srcmap = sass_import_take_srcmap(include);
214224
if (message) {
215225
if (line == string::npos && column == string::npos) error(message, pstate);
216226
else error(message, ParserState(message, source, Position(line, column)));
217227
} else if (source) {
218228
if (file) {
219-
ctx.add_source(file, inc_path, source);
229+
ctx.add_source(file, load_path, source);
220230
imp->files().push_back(file);
221231
} else {
222-
ctx.add_source(inc_path, inc_path, source);
223-
imp->files().push_back(inc_path);
232+
ctx.add_source(load_path, load_path, source);
233+
imp->files().push_back(load_path);
224234
}
225235
} else if(file) {
226-
add_single_file(imp, file);
236+
import_single_file(imp, file);
227237
}
228238
++includes;
229239
}
230240
// deallocate returned memory
231241
sass_delete_import_list(list);
232-
// parse next import
233-
continue;
242+
// break import chain
243+
has_custom_import = true;
234244
}
235245
}
236246

237-
if (!unquote(import_path).substr(0, 7).compare("http://") ||
238-
!unquote(import_path).substr(0, 8).compare("https://") ||
239-
!unquote(import_path).substr(0, 2).compare("//"))
240-
{
241-
imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
242-
}
243-
else {
244-
add_single_file(imp, import_path);
247+
if (!has_custom_import) {
248+
// push single file import
249+
import_single_file(imp, import_path);
245250
}
246251

247252
}
@@ -621,14 +626,14 @@ namespace Sass {
621626
Simple_Selector* Parser::parse_simple_selector()
622627
{
623628
lex < css_comments >();
624-
if (lex< id_name >() || lex< class_name >()) {
629+
if (lex< alternatives < id_name, class_name > >()) {
625630
return new (ctx.mem) Selector_Qualifier(pstate, unquote(lexed));
626631
}
627-
else if (lex< quoted_string >() || lex< number >()) {
632+
else if (lex< quoted_string >()) {
628633
return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
629634
}
630-
else if (lex< exactly < sel_deep_kwd > >()) {
631-
return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
635+
else if (lex< alternatives < number, kwd_sel_deep > >()) {
636+
return new (ctx.mem) Type_Selector(pstate, lexed);
632637
}
633638
else if (peek< pseudo_not >()) {
634639
return parse_negated_selector();

parser.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace Sass {
2525
class Parser : public ParserState {
2626
private:
2727
void add_single_file (Import* imp, string import_path);
28+
void import_single_file (Import* imp, string import_path);
2829
public:
2930
class AST_Node;
3031

plugins.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace Sass {
4646

4747
typedef const char* (*__plugin_version__)(void);
4848
typedef Sass_C_Function_List (*__plugin_load_fns__)(void);
49+
typedef Sass_C_Importer_List (*__plugin_load_imps__)(void);
4950

5051
if (LOAD_LIB(plugin, path))
5152
{
@@ -60,6 +61,12 @@ namespace Sass {
6061
Sass_C_Function_List fns = plugin_load_functions();
6162
while (fns && *fns) { functions.push_back(*fns); ++ fns; }
6263
}
64+
// try to get import address for "libsass_load_importers"
65+
if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers"))
66+
{
67+
Sass_C_Importer_List imps = plugin_load_importers();
68+
while (imps && *imps) { importers.push_back(*imps); ++ imps; }
69+
}
6370
// success
6471
return true;
6572
}

plugins.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ namespace Sass {
4242
size_t load_plugins(const string& path);
4343

4444
public: // public accessors
45-
// const vector<Sass_C_Import_Callback> get_importers(void) { return importers; };
46-
const vector<Sass_C_Function_Callback> get_functions(void) { return functions; };
45+
const vector<Sass_C_Importer_Call> get_importers(void) { return importers; };
46+
const vector<Sass_C_Function_Call> get_functions(void) { return functions; };
4747

4848
private: // private vars
49-
// vector<Sass_C_Import_Callback> importers;
50-
vector<Sass_C_Function_Callback> functions;
49+
vector<Sass_C_Importer_Call> importers;
50+
vector<Sass_C_Function_Call> functions;
5151

5252
};
5353

prelexer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ namespace Sass {
197197
return sequence<exactly<'@'>, identifier>(src);
198198
}
199199

200+
const char* kwd_sel_deep(const char* src) {
201+
return word<sel_deep_kwd>(src);
202+
}
203+
200204
const char* kwd_import(const char* src) {
201205
return word<import_kwd>(src);
202206
}

prelexer.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ namespace Sass {
172172
const char* identifier_alnums(const char* src);
173173
// Match selector names.
174174
// const char* sel_ident(const char* src);
175+
const char* kwd_sel_deep(const char* src);
176+
175177
// Match interpolant schemas
176178
const char* identifier_schema(const char* src);
177179
const char* value_schema(const char* src);

0 commit comments

Comments
 (0)