aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--complete.c18
-rw-r--r--env.c3
-rw-r--r--function.c12
-rw-r--r--parse_util.c175
-rw-r--r--parse_util.h28
-rw-r--r--parser.c13
-rw-r--r--share/functions/grep.fish2
7 files changed, 207 insertions, 44 deletions
diff --git a/complete.c b/complete.c
index 79102a9c..4cda7c8d 100644
--- a/complete.c
+++ b/complete.c
@@ -233,7 +233,6 @@ static hash_table_t *condition_cache=0;
*/
static string_buffer_t *get_desc_buff=0;
-
/**
This command clears the cache of condition tests created by \c condition_test().
*/
@@ -354,7 +353,7 @@ void complete_destroy()
suffix_hash=0;
}
- parse_util_load_reset(L"fish_complete_path");
+ parse_util_load_reset( L"fish_complete_path", 0 );
}
@@ -1551,7 +1550,10 @@ static void complete_load_handler( const wchar_t *cmd )
void complete_load( const wchar_t *name, int reload )
{
- parse_util_load( name, L"fish_complete_path", &complete_load_handler, reload );
+ parse_util_load( name,
+ L"fish_complete_path",
+ &complete_load_handler,
+ reload );
}
/**
@@ -1955,20 +1957,18 @@ void complete( const wchar_t *cmd,
wchar_t *buff;
tokenizer tok;
wchar_t *current_token=0, *current_command=0, *prev_token=0;
-
int on_command=0;
int pos;
-
int done=0;
-
- int cursor_pos = wcslen(cmd );
+ int cursor_pos;
CHECK( cmd, );
CHECK( comp, );
// debug( 1, L"Complete '%ls'", cmd );
-
-
+
+ cursor_pos = wcslen(cmd );
+
/**
If we are completing a variable name or a tilde expansion user
name, we do that and return. No need for any other competions.
diff --git a/env.c b/env.c
index a7367772..47761f97 100644
--- a/env.c
+++ b/env.c
@@ -317,9 +317,6 @@ static void handle_locale()
if( is_interactive )
{
- complete_destroy();
- complete_init();
-
debug( 0, _(L"Changing language to English") );
}
}
diff --git a/function.c b/function.c
index 345e4aa9..5989fd22 100644
--- a/function.c
+++ b/function.c
@@ -225,7 +225,7 @@ void function_remove( const wchar_t *name )
event_t ev;
CHECK( name, );
-
+
hash_remove( &function,
name,
&key,
@@ -241,6 +241,16 @@ void function_remove( const wchar_t *name )
event_remove( &ev );
clear_function_entry( key, d );
+
+ /*
+ Notify the autoloader that the specified function is erased, but
+ only if this call to fish_remove is not made by the autoloader
+ itself.
+ */
+ if( !is_autoload )
+ {
+ parse_util_unload( name, L"fish_function_path", 0 );
+ }
}
const wchar_t *function_get_definition( const wchar_t *argv )
diff --git a/parse_util.c b/parse_util.c
index 55190073..164269c0 100644
--- a/parse_util.c
+++ b/parse_util.c
@@ -29,10 +29,37 @@
#include "intern.h"
#include "exec.h"
#include "env.h"
+#include "translate.h"
#include "wildcard.h"
#include "halloc_util.h"
/**
+ A structure representing the autoload state for a specific variable, e.g. fish_complete_path
+*/
+typedef struct
+{
+ /**
+ A table containing the modification times of all loaded
+ files. Failed loads (non-existing files) have modification time
+ 0.
+ */
+ hash_table_t load_time;
+ /**
+ A string containg the path used to find any files to load. If
+ this differs from the current environment variable, the
+ autoloader needs to drop all loaded files and reload them.
+ */
+ wchar_t *old_path;
+ /**
+ A table containing all the files that are currently being
+ loaded. This is here to help prevent recursion.
+ */
+ hash_table_t is_loading;
+}
+ autoload_t;
+
+
+/**
Set of files which have been autoloaded
*/
static hash_table_t *all_loaded=0;
@@ -448,20 +475,32 @@ void parse_util_token_extent( const wchar_t *buff,
/**
Free hash value, but not hash key
*/
-static void clear_hash_value( void *key, void *data )
+static void clear_hash_value( void *key, void *data, void *aux )
{
+ if( aux )
+ {
+ wchar_t *name = (wchar_t *)key;
+ void (*handler)(const wchar_t *)= (void (*)(const wchar_t *))aux;
+ handler( name );
+ }
+
free( (void *)data );
}
/**
Part of the autoloader cleanup
*/
-static void clear_loaded_entry( void *key, void *data )
+static void clear_loaded_entry( void *key,
+ void *data,
+ void *handler )
{
- hash_table_t *loaded = (hash_table_t *)data;
- hash_foreach( loaded,
- &clear_hash_value );
- hash_destroy( loaded );
+ autoload_t *loaded = (autoload_t *)data;
+ hash_foreach2( &loaded->load_time,
+ &clear_hash_value,
+ handler );
+ hash_destroy( &loaded->load_time );
+
+ free( loaded->old_path );
free( loaded );
free( (void *)key );
}
@@ -475,8 +514,9 @@ static void parse_util_destroy()
{
if( all_loaded )
{
- hash_foreach( all_loaded,
- &clear_loaded_entry );
+ hash_foreach2( all_loaded,
+ &clear_loaded_entry,
+ 0 );
hash_destroy( all_loaded );
free( all_loaded );
@@ -484,18 +524,61 @@ static void parse_util_destroy()
}
}
-void parse_util_load_reset( const wchar_t *path_var )
+void parse_util_load_reset( const wchar_t *path_var_name,
+ void (*on_load)(const wchar_t *cmd) )
{
+ wchar_t *path_var;
+
+ CHECK( path_var_name, );
+ path_var = env_get( path_var_name );
+
+ if( !path_var )
+ return;
+
if( all_loaded )
{
void *key, *data;
- hash_remove( all_loaded, path_var, &key, &data );
+ hash_remove( all_loaded, path_var_name, &key, &data );
if( key )
- clear_loaded_entry( key, data );
+ clear_loaded_entry( key, data, (void *)on_load );
}
}
+int parse_util_unload( const wchar_t *cmd,
+ const wchar_t *path_var_name,
+ void (*on_load)(const wchar_t *cmd) )
+{
+ autoload_t *loaded;
+ void *val;
+
+ CHECK( path_var_name, 0 );
+ CHECK( cmd, 0 );
+
+ if( !all_loaded )
+ {
+ return 0;
+ }
+
+ loaded = (autoload_t *)hash_get( all_loaded, path_var_name );
+
+ if( !loaded )
+ {
+ return 0;
+ }
+
+ hash_remove( &loaded->load_time, cmd, 0, &val );
+ if( val )
+ {
+ if( on_load )
+ {
+ on_load( (wchar_t *)val );
+ }
+ free( val );
+ }
+
+ return !!val;
+}
int parse_util_load( const wchar_t *cmd,
const wchar_t *path_var_name,
@@ -508,16 +591,22 @@ int parse_util_load( const wchar_t *cmd,
int i;
time_t *tm;
int reloaded = 0;
- hash_table_t *loaded;
+ autoload_t *loaded;
- wchar_t *path_var = env_get( path_var_name );
+ wchar_t *path_var;
+ CHECK( path_var_name, 0 );
+ CHECK( cmd, 0 );
+
+ path_var = env_get( path_var_name );
+
/*
Do we know where to look
*/
-
if( !path_var )
+ {
return 0;
+ }
if( !all_loaded )
{
@@ -530,23 +619,52 @@ int parse_util_load( const wchar_t *cmd,
hash_init( all_loaded, &hash_wcs_func, &hash_wcs_cmp );
}
- loaded = (hash_table_t *)hash_get( all_loaded, path_var_name );
-
- if( !loaded )
+ loaded = (autoload_t *)hash_get( all_loaded, path_var_name );
+
+ if( loaded )
+ {
+ if( hash_get( &loaded->is_loading, cmd ) )
+ {
+ debug( 0, _(L"Could not autoload item %ls, it is already being autoloaded. This is a circular dependency in the autoloading scripts, please remove it."), cmd );
+ return 1;
+ }
+
+ /*
+ Check if the lookup path has changed. If so, drop all loaded
+ files and start from scratch.
+ */
+ if( wcscmp( path_var, loaded->old_path ) != 0 )
+ {
+ parse_util_load_reset( path_var_name, on_load);
+ reload = parse_util_load( cmd, path_var_name, on_load, reload );
+ return reload;
+ }
+ }
+ else
{
- loaded = malloc( sizeof( hash_table_t ) );
+ /*
+ We have never tried to autoload using this name before, set up initial data
+ */
+ loaded = malloc( sizeof( autoload_t ) );
if( !loaded )
{
DIE_MEM();
}
- hash_init( loaded, &hash_wcs_func, &hash_wcs_cmp );
+ hash_init( &loaded->load_time, &hash_wcs_func, &hash_wcs_cmp );
hash_put( all_loaded, wcsdup(path_var_name), loaded );
+
+ hash_init( &loaded->is_loading, &hash_wcs_func, &hash_wcs_cmp );
+
+ loaded->old_path = wcsdup( path_var );
}
+ hash_put( &loaded->is_loading, cmd, cmd );
+
+
/*
Get modification time of file
*/
- tm = (time_t *)hash_get( loaded, cmd );
+ tm = (time_t *)hash_get( &loaded->load_time, cmd );
/*
Did we just check this?
@@ -555,6 +673,7 @@ int parse_util_load( const wchar_t *cmd,
{
if(time(0)-tm[1]<=1)
{
+ hash_remove( &loaded->is_loading, cmd, 0, 0 );
return 0;
}
}
@@ -563,7 +682,10 @@ int parse_util_load( const wchar_t *cmd,
Return if already loaded and we are skipping reloading
*/
if( !reload && tm )
+ {
+ hash_remove( &loaded->is_loading, cmd, 0, 0 );
return 0;
+ }
if( !path_list )
path_list = al_halloc( global_context);
@@ -601,7 +723,7 @@ int parse_util_load( const wchar_t *cmd,
tm[0] = buf.st_mtime;
tm[1] = time(0);
- hash_put( loaded,
+ hash_put( &loaded->load_time,
intern( cmd ),
tm );
@@ -634,12 +756,13 @@ int parse_util_load( const wchar_t *cmd,
tm[0] = 0;
tm[1] = time(0);
- hash_put( loaded, intern( cmd ), tm );
+ hash_put( &loaded->load_time, intern( cmd ), tm );
}
al_foreach( path_list, &free );
al_truncate( path_list, 0 );
-
+
+ hash_remove( &loaded->is_loading, cmd, 0, 0 );
return reloaded;
}
@@ -670,7 +793,11 @@ void parse_util_set_argv( wchar_t **argv )
wchar_t *parse_util_unescape_wildcards( const wchar_t *str )
{
wchar_t *in, *out;
- wchar_t *unescaped = wcsdup(str);
+ wchar_t *unescaped;
+
+ CHECK( str, 0 );
+
+ unescaped = wcsdup(str);
if( !unescaped )
DIE_MEM();
diff --git a/parse_util.h b/parse_util.h
index 23b9b88f..c9115107 100644
--- a/parse_util.h
+++ b/parse_util.h
@@ -95,10 +95,11 @@ int parse_util_lineno( const wchar_t *str, int len );
/**
Autoload the specified file, if it exists in the specified path. Do
- not load it multiple times unless it's timestamp changes.
+ not load it multiple times unless it's timestamp changes or
+ parse_util_unload is called.
\param cmd the filename to search for. The suffix '.fish' is always added to this name
- \param path_var_name the name of an environment variable containing a search path
+ \param path_var_name the environment variable giving the search path
\param on_load a callback function to run if a suitable file is found, which has not already been run
\param reload wheter to recheck file timestamps on already loaded files
*/
@@ -108,9 +109,28 @@ int parse_util_load( const wchar_t *cmd,
int reload );
/**
- Reset the loader for the specified path variable
+ Reset the loader for the specified path variable. This will cause
+ all information on loaded files in the specified directory to be
+ reset.
+
+ \param path_var_name the environment variable giving the search path
+ \param on_load the callback function to use when a file is reloaded
+ \param on_load the callback function to call if the file has been previously loaded
+*/
+void parse_util_load_reset( const wchar_t *path_var_name,
+ void (*on_load)(const wchar_t *cmd) );
+
+/**
+ Tell the autoloader that the specified file, in the specified path,
+ is no longer loaded.
+
+ \param cmd the filename to search for. The suffix '.fish' is always added to this name
+ \param path_var_name the environment variable giving the search path
+ \return non-zero if the file was removed, zero if the file had not yet been loaded
*/
-void parse_util_load_reset( const wchar_t *path_var );
+int parse_util_unload( const wchar_t *cmd,
+ const wchar_t *path_var_name,
+ void (*on_load)(const wchar_t *cmd) );
/**
Set the argv environment variable to the specified null-terminated
diff --git a/parser.c b/parser.c
index 85851c9f..1ab7972f 100644
--- a/parser.c
+++ b/parser.c
@@ -443,11 +443,19 @@ void parser_push_block( int type )
blocks should always be skipped. Rather complicated... :-(
*/
new->skip=current_block?current_block->skip:0;
+
+ /*
+ Type TOP and SUBST are never skipped
+ */
if( type == TOP || type == SUBST )
{
new->skip = 0;
}
- if( type == FAKE )
+
+ /*
+ Fake blocks and function definition blocks are never executed
+ */
+ if( type == FAKE || type == FUNCTION_DEF )
{
new->skip = 1;
}
@@ -2065,11 +2073,12 @@ static int parse_job( process_t *p,
forbid = (wchar_t *)(al_get_count( forbidden_function)?al_peek( forbidden_function ):0);
nxt_forbidden = forbid && (wcscmp( forbid, nxt) == 0 );
-
+
/*
Make feeble attempt to avoid infinite recursion. Will at
least catch some accidental infinite recursion calls.
*/
+
if( function_exists( nxt ) && !nxt_forbidden)
{
/*
diff --git a/share/functions/grep.fish b/share/functions/grep.fish
index d34b288d..60e83b20 100644
--- a/share/functions/grep.fish
+++ b/share/functions/grep.fish
@@ -2,7 +2,7 @@
# Match colors for grep, if supported
#
-if grep --color=auto --help 1>/dev/null 2>/dev/null
+if command grep --color=auto --help 1>/dev/null 2>/dev/null
if not set -q GREP_COLOR
set -gx GREP_COLOR '97;45'
end