Changes related to supporting "intern scripts." These are scripts that used to be installed in /share/functions, but now are just compiled-in strings. This should reduce the amount of I/O done at launch time.

This commit is contained in:
ridiculousfish 2012-01-05 11:44:57 -08:00
parent f78c4fa751
commit 57c9eeeecb
2 changed files with 98 additions and 67 deletions

View File

@ -66,7 +66,7 @@ funcs.sort(key=cfunc.cfunc_name)
fd = open('builtin_scripts.h', 'w') fd = open('builtin_scripts.h', 'w')
fd.write('/* This file is generated by internalize_scripts.py */\n\n') fd.write('/* This file is generated by internalize_scripts.py */\n\n')
fd.write("""struct builtin_script_t { fd.write("""struct builtin_script_t {
const char *name; const wchar_t *name;
const char *def; const char *def;
};""") };""")
@ -85,7 +85,7 @@ for func in funcs:
fd.write('\n') fd.write('\n')
# Output the refs # Output the refs
func_refs = ["{%s, %s}" % (stringize(func.name), func.cfunc_name()) for func in funcs] func_refs = ["{L%s, %s}" % (stringize(func.name), func.cfunc_name()) for func in funcs]
fd.write('const struct builtin_script_t internal_function_scripts[%d] =\n' % len(funcs)) fd.write('const struct builtin_script_t internal_function_scripts[%d] =\n' % len(funcs))
fd.write('{\n\t') fd.write('{\n\t')
fd.write(',\n\t'.join(func_refs)) fd.write(',\n\t'.join(func_refs))

View File

@ -20,6 +20,7 @@
#include <wchar.h> #include <wchar.h>
#include <map> #include <map>
#include <set> #include <set>
#include <algorithm>
#include <time.h> #include <time.h>
#include <assert.h> #include <assert.h>
@ -871,7 +872,7 @@ int parse_util_load( const wcstring &cmd,
/* Figure out which builtin-scripts array to search (if any) */ /* Figure out which builtin-scripts array to search (if any) */
const builtin_script_t *builtins = NULL; const builtin_script_t *builtins = NULL;
size_t builtin_count = 0; size_t builtin_count = 0;
if (cmd == L"fish_function_path") if (path_var_name == L"fish_function_path")
{ {
builtins = internal_function_scripts; builtins = internal_function_scripts;
builtin_count = sizeof internal_function_scripts / sizeof *internal_function_scripts; builtin_count = sizeof internal_function_scripts / sizeof *internal_function_scripts;
@ -908,6 +909,11 @@ int parse_util_load( const wcstring &cmd,
return res; return res;
} }
static bool script_name_precedes_script_name(const builtin_script_t &script1, const builtin_script_t &script2)
{
return wcscmp(script1.name, script2.name) < 0;
}
/** /**
This internal helper function does all the real work. By using two This internal helper function does all the real work. By using two
functions, the internal function can return on various places in functions, the internal function can return on various places in
@ -915,7 +921,7 @@ int parse_util_load( const wcstring &cmd,
*/ */
static int parse_util_load_internal( const wcstring &cmd, static int parse_util_load_internal( const wcstring &cmd,
const struct builtin_script_t *builtin_scripts, const builtin_script_t *builtin_scripts,
size_t builtin_script_count, size_t builtin_script_count,
void (*on_load)(const wchar_t *cmd), void (*on_load)(const wchar_t *cmd),
int reload, int reload,
@ -929,7 +935,6 @@ static int parse_util_load_internal( const wcstring &cmd,
/* Get the function */ /* Get the function */
autoload_function_t * func = loaded.get_function_with_name(cmd); autoload_function_t * func = loaded.get_function_with_name(cmd);
/* Return if already loaded and we are skipping reloading */ /* Return if already loaded and we are skipping reloading */
if( !reload && func ) if( !reload && func )
return 0; return 0;
@ -937,73 +942,99 @@ static int parse_util_load_internal( const wcstring &cmd,
/* Nothing to do if we just checked it */ /* Nothing to do if we just checked it */
if (func && time(NULL) - func->load_time <= 1) if (func && time(NULL) - func->load_time <= 1)
return 0; return 0;
/*
Look for built-in scripts.
*/
/* /* The source of the script will end up here */
Iterate over path searching for suitable completion files wcstring script_source;
*/ bool has_script_source = false;
for( i=0; i<path_list.size(); i++ )
{ /*
struct stat buf; Look for built-in scripts via a binary search
wcstring next = path_list.at(i); */
wcstring path = next + L"/" + cmd + L".fish"; const builtin_script_t *matching_builtin_script = NULL;
if (builtin_script_count > 0)
{
const builtin_script_t test_script = {cmd.c_str(), NULL};
const builtin_script_t *array_end = builtin_scripts + builtin_script_count;
const builtin_script_t *found = std::lower_bound(builtin_scripts, array_end, test_script, script_name_precedes_script_name);
if (found != array_end && ! wcscmp(found->name, test_script.name))
{
/* We found it */
matching_builtin_script = found;
}
}
if (matching_builtin_script) {
has_script_source = true;
script_source = str2wcstring(matching_builtin_script->def);
}
if (! has_script_source)
{
/*
Iterate over path searching for suitable completion files
*/
for( i=0; i<path_list.size(); i++ )
{
struct stat buf;
wcstring next = path_list.at(i);
wcstring path = next + L"/" + cmd + L".fish";
if( (wstat( path.c_str(), &buf )== 0) && if( (wstat( path.c_str(), &buf )== 0) &&
(waccess( path.c_str(), R_OK ) == 0) ) (waccess( path.c_str(), R_OK ) == 0) )
{ {
if( !func || (func->modification_time != buf.st_mtime ) ) if( !func || (func->modification_time != buf.st_mtime ) )
{ {
wcstring esc = escape_string(path, 1); wcstring esc = escape_string(path, 1);
wcstring src_cmd = L". " + esc; script_source = L". " + esc;
has_script_source = true;
if( !func )
func = loaded.create_function_with_name(cmd); if( !func )
func = loaded.create_function_with_name(cmd);
func->modification_time = buf.st_mtime; func->modification_time = buf.st_mtime;
func->load_time = time(NULL); func->load_time = time(NULL);
if( on_load )
on_load(cmd.c_str());
reloaded = 1;
}
else if( func )
{
/*
If we are rechecking an autoload file, and it hasn't
changed, update the 'last check' timestamp.
*/
func->load_time = time(NULL);
}
if( on_load ) break;
on_load(cmd.c_str()); }
}
/*
Source the completion file for the specified completion
*/
if( exec_subshell( src_cmd.c_str(), 0 ) == -1 )
{
/*
Do nothing on failiure
*/
}
reloaded = 1;
}
else if( func )
{
/*
If we are rechecking an autoload file, and it hasn't
changed, update the 'last check' timestamp.
*/
func->load_time = time(NULL);
}
break;
}
}
/* /*
If no file was found we insert a placeholder function. Later we only If no file was found we insert a placeholder function. Later we only
research if the current time is at least five seconds later. research if the current time is at least five seconds later.
This way, the files won't be searched over and over again. This way, the files won't be searched over and over again.
*/ */
if( !func ) if( !func )
{ {
func = loaded.create_function_with_name(cmd); func = loaded.create_function_with_name(cmd);
func->load_time = time(NULL); func->load_time = time(NULL);
func->is_placeholder = true; func->is_placeholder = true;
} }
}
/* If we have a script, either built-in or a file source, then run it */
if (has_script_source)
{
if( exec_subshell( script_source.c_str(), 0 ) == -1 )
{
/*
Do nothing on failiure
*/
}
}
return reloaded; return reloaded;
} }