Autoloaded functions

darcs-hash:20060208092005-ac50b-8e784f79a4e158c8c15b553fad85002dccc7bd03.gz
This commit is contained in:
axel 2006-02-08 19:20:05 +10:00
parent 47b652c76e
commit 73a9c8bcb8
31 changed files with 1319 additions and 1229 deletions

View file

@ -171,6 +171,8 @@ TESTS_DIR_FILES := $(TEST_IN) $(TEST_IN:.in=.out) $(TEST_IN:.in=.err) \
COMPLETIONS_DIR_FILES := $(wildcard init/completions/*.fish)
FUNCTIONS_DIR_FILES := $(wildcard init/functions/*.fish)
# Programs to build
PROGRAMS:=fish set_color @XSEL@ @SEQ_FALLBACK@ mimedb count fish_pager fishd
@ -262,7 +264,7 @@ doc.h:$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC) doc_src/doc.hdr
fi
# Create a template translation object
messages.pot: *.c *.h init/*.in init/*.fish init/completions/*.fish seq
messages.pot: *.c *.h init/*.in init/*.fish init/completions/*.fish init/functions/*.fish seq
if test $(HAVE_GETTEXT) = 1;then \
xgettext -k_ -kN_ -kcomplete_desc *.c *.h -o messages.pot; \
if ! xgettext -j -k_ -LShell init/*.in init/*.fish init/completions/*.fish seq -o messages.pot; then \
@ -346,6 +348,7 @@ install: all install-translations
done;
$(INSTALL) -m 755 -d $(DESTDIR)$(sysconfdir)$(fishdir)
$(INSTALL) -m 755 -d $(DESTDIR)$(sysconfdir)$(fishdir)/completions
$(INSTALL) -m 755 -d $(DESTDIR)$(sysconfdir)$(fishdir)/functions
$(INSTALL) -m 644 init/fish $(DESTDIR)$(sysconfdir)$(fishfile)
for i in $(INIT_DIR_INSTALL); do \
$(INSTALL) -m 644 $$i $(DESTDIR)$(sysconfdir)$(fishdir); \
@ -353,6 +356,9 @@ install: all install-translations
for i in $(COMPLETIONS_DIR_FILES); do \
$(INSTALL) -m 644 $$i $(DESTDIR)$(sysconfdir)$(fishdir)/completions/; \
done;
for i in $(FUNCTIONS_DIR_FILES); do \
$(INSTALL) -m 644 $$i $(DESTDIR)$(sysconfdir)$(fishdir)/functions/; \
done;
$(INSTALL) -m 644 init/fish_inputrc $(DESTDIR)$(sysconfdir)$(fishinputfile);
$(INSTALL) -m 755 -d $(DESTDIR)$(docdir)
for i in user_doc/html/* ChangeLog; do \
@ -450,18 +456,20 @@ depend:
#
# Uses install instead of mkdir so build won't fail if the directory
# exists
fish-@PACKAGE_VERSION@.tar: $(DOC_SRC_DIR_FILES) $(MAIN_DIR_FILES) $(INIT_DIR_FILES) $(TEST_DIR_FILES) $(COMPLETIONS_DIR_FILES) ChangeLog
fish-@PACKAGE_VERSION@.tar: $(DOC_SRC_DIR_FILES) $(MAIN_DIR_FILES) $(INIT_DIR_FILES) $(TEST_DIR_FILES) $(FUNCTIONS_DIR_FILES) $(COMPLETIONS_DIR_FILES) ChangeLog
rm -rf fish-@PACKAGE_VERSION@
$(INSTALL) -d fish-@PACKAGE_VERSION@
$(INSTALL) -d fish-@PACKAGE_VERSION@/doc_src
$(INSTALL) -d fish-@PACKAGE_VERSION@/init
$(INSTALL) -d fish-@PACKAGE_VERSION@/init/completions
$(INSTALL) -d fish-@PACKAGE_VERSION@/init/functions
$(INSTALL) -d fish-@PACKAGE_VERSION@/tests
$(INSTALL) -d fish-@PACKAGE_VERSION@/po
cp -f $(DOC_SRC_DIR_FILES) fish-@PACKAGE_VERSION@/doc_src
cp -f $(MAIN_DIR_FILES) fish-@PACKAGE_VERSION@/
cp -f $(INIT_DIR_FILES) fish-@PACKAGE_VERSION@/init/
cp -f $(COMPLETIONS_DIR_FILES) fish-@PACKAGE_VERSION@/init/completions/
cp -f $(FUNCTIONS_DIR_FILES) fish-@PACKAGE_VERSION@/init/functions/
cp -f $(TESTS_DIR_FILES) fish-@PACKAGE_VERSION@/tests/
cp -f $(TRANSLATIONS_SRC) fish-@PACKAGE_VERSION@/po/
tar -c fish-@PACKAGE_VERSION@ >fish-@PACKAGE_VERSION@.tar

View file

@ -287,6 +287,7 @@ wchar_t *str2wcs( const char *in )
{
return out;
}
default:
{
in_pos += res;

View file

@ -215,11 +215,6 @@ static hash_table_t *suffix_hash=0;
*/
static hash_table_t *condition_cache=0;
/**
Set of commands for which completions have already been loaded
*/
static hash_table_t *loaded_completions=0;
/**
String buffer used by complete_get_desc
*/
@ -326,15 +321,6 @@ static void clear_hash_entry( const void *key, const void *data )
free( (void *)data );
}
/**
Free hash value, but not hash key
*/
static void clear_hash_value( const void *key, const void *data )
{
free( (void *)data );
}
void complete_destroy()
{
complete_entry *i=first_entry, *prev;
@ -355,15 +341,6 @@ void complete_destroy()
suffix_hash=0;
}
if( loaded_completions )
{
hash_foreach( loaded_completions,
&clear_hash_value );
hash_destroy( loaded_completions );
free( loaded_completions );
loaded_completions = 0;
}
if( get_desc_buff )
{
sb_destroy( get_desc_buff );
@ -1464,117 +1441,15 @@ static int short_ok( wchar_t *arg,
return 1;
}
void complete_load( wchar_t *cmd,
int reload )
static void complete_load_handler( const wchar_t *cmd )
{
const wchar_t *path_var;
array_list_t path_list;
int i;
string_buffer_t path;
time_t *tm;
/*
First check that the specified completion hasn't already been loaded
*/
if( !loaded_completions )
{
loaded_completions = malloc( sizeof( hash_table_t ) );
if( !loaded_completions )
{
die_mem();
}
hash_init( loaded_completions, &hash_wcs_func, &hash_wcs_cmp );
}
/*
Get modification time of file
*/
tm = (time_t *)hash_get( loaded_completions, cmd );
/*
Return if already loaded and we are skipping reloading
*/
if( !reload && tm )
return;
/*
Do we know where to look for completions?
*/
path_var = env_get( L"fish_complete_path" );
if( !path_var )
return;
al_init( &path_list );
sb_init( &path );
expand_variable_array( path_var, &path_list );
/*
Iterate over path searching for suitable completion files
*/
for( i=0; i<al_get_count( &path_list ); i++ )
{
struct stat buf;
wchar_t *next = (wchar_t *)al_get( &path_list, i );
sb_clear( &path );
sb_append2( &path, next, L"/", cmd, L".fish", (void *)0 );
if( (wstat( (wchar_t *)path.buff, &buf )== 0) &&
(waccess( (wchar_t *)path.buff, R_OK ) == 0) )
{
if( !tm || (*tm != buf.st_mtime ) )
{
wchar_t *esc = escape( (wchar_t *)path.buff, 1 );
wchar_t *src_cmd = wcsdupcat( L". ", esc );
if( !tm )
{
tm = malloc(sizeof(time_t));
if( !tm )
die_mem();
}
*tm = buf.st_mtime;
hash_put( loaded_completions,
intern( cmd ),
tm );
free( esc );
complete_remove( cmd, COMMAND, 0, 0 );
/*
Source the completion file for the specified completion
*/
exec_subshell( src_cmd, 0 );
free(src_cmd);
break;
}
}
}
/*
If no file was found we insert a last modified time of Jan 1, 1970.
This way, the completions_path wont be searched over and over again
when reload is set to 0.
*/
if( !tm )
{
tm = malloc(sizeof(time_t));
if( !tm )
die_mem();
*tm = 0;
hash_put( loaded_completions, intern( cmd ), tm );
}
sb_destroy( &path );
al_foreach( &path_list, (void (*)(const void *))&free );
al_destroy( &path_list );
}
void complete_load( const wchar_t *name, int reload )
{
parse_util_load( name, env_get( L"fish_complete_path" ), &complete_load_handler, reload );
}
/**
Find completion for the argument str of command cmd_orig with

View file

@ -162,6 +162,6 @@ int complete_is_valid_argument( const wchar_t *str,
\param cmd the command for which to load command-specific completions
\param reload should the commands completions be reloaded, even if they where previously loaded. (This is set to true on actual completions, so that changed completion are updated in running shells)
*/
void complete_load( wchar_t *cmd, int reload );
void complete_load( const wchar_t *cmd, int reload );
#endif

View file

@ -67,6 +67,8 @@ fi
%config %_sysconfdir/fish.d/fish_*.fish
%dir %_sysconfdir/fish.d/completions
%config %_sysconfdir/fish.d/completions/*.fish
%dir %_sysconfdir/fish.d/functions
%config %_sysconfdir/fish.d/functions/*.fish
%_datadir/locale/*/LC_MESSAGES/fish.mo
%changelog

View file

@ -19,6 +19,7 @@
#include "event.h"
#include "reader.h"
#include "parse_util.h"
#include "env.h"
/**
@ -33,6 +34,7 @@ typedef struct
const wchar_t *definition_file;
int definition_offset;
int is_binding;
int is_autoload;
}
function_data_t;
@ -40,6 +42,31 @@ typedef struct
Table containing all functions
*/
static hash_table_t function;
static int is_autoload = 0;
static int load( const wchar_t *name )
{
int was_autoload = is_autoload;
int res;
function_data_t *data;
data = (function_data_t *)hash_get( &function, name );
if( data && !data->is_autoload )
return 0;
is_autoload = 1;
res = parse_util_load( name,
env_get( L"fish_function_path" ),
&function_remove,
1 );
is_autoload = was_autoload;
return res;
}
static void load_all()
{
}
/**
Free all contents of an entry to the function hash table
@ -92,6 +119,7 @@ void function_add( const wchar_t *name,
d->desc = desc?wcsdup( desc ):0;
d->is_binding = is_binding;
d->definition_file = intern(reader_current_filename());
d->is_autoload = is_autoload;
hash_put( &function, intern(name), d );
@ -104,6 +132,11 @@ void function_add( const wchar_t *name,
int function_exists( const wchar_t *cmd )
{
function_data_t *data;
if( parser_is_reserved(cmd) )
return 0;
load( cmd );
return (hash_get(&function, cmd) != 0 );
}
@ -130,8 +163,9 @@ void function_remove( const wchar_t *name )
const wchar_t *function_get_definition( const wchar_t *argv )
{
function_data_t *data =
(function_data_t *)hash_get( &function, argv );
function_data_t *data;
load( argv );
data = (function_data_t *)hash_get( &function, argv );
if( data == 0 )
return 0;
return data->cmd;
@ -139,8 +173,9 @@ const wchar_t *function_get_definition( const wchar_t *argv )
const wchar_t *function_get_desc( const wchar_t *argv )
{
function_data_t *data =
(function_data_t *)hash_get( &function, argv );
function_data_t *data;
load( argv );
data = (function_data_t *)hash_get( &function, argv );
if( data == 0 )
return 0;
@ -149,8 +184,9 @@ const wchar_t *function_get_desc( const wchar_t *argv )
void function_set_desc( const wchar_t *name, const wchar_t *desc )
{
function_data_t *data =
(function_data_t *)hash_get( &function, name );
function_data_t *data;
load( name );
data = (function_data_t *)hash_get( &function, name );
if( data == 0 )
return;
@ -173,6 +209,8 @@ static void get_names_internal( const void *key,
void function_get_names( array_list_t *list, int get_hidden )
{
load_all();
if( get_hidden )
hash_get_keys( &function, list );
else
@ -182,8 +220,9 @@ void function_get_names( array_list_t *list, int get_hidden )
const wchar_t *function_get_definition_file( const wchar_t *argv )
{
function_data_t *data =
(function_data_t *)hash_get( &function, argv );
function_data_t *data;
load( argv );
data = (function_data_t *)hash_get( &function, argv );
if( data == 0 )
return 0;
@ -193,8 +232,9 @@ const wchar_t *function_get_definition_file( const wchar_t *argv )
int function_get_definition_offset( const wchar_t *argv )
{
function_data_t *data =
(function_data_t *)hash_get( &function, argv );
function_data_t *data;
load( argv );
data = (function_data_t *)hash_get( &function, argv );
if( data == 0 )
return -1;

View file

@ -87,6 +87,8 @@ if test 1 = "@HAVE_GETTEXT@"
end
end
set -g fish_function_path $PWD/fish.d/functions
#
# Load additional initialization files
#

View file

@ -14,16 +14,6 @@ end
set -g fish_complete_path @SYSCONFDIR@/fish.d/completions ~/.fish.d/completions
# Knowing the location of the whatis database speeds up command
# description lookup.
for i in /var/cache/man/{whatis,windex} /usr{,/local}{,/share}/man/{whatis,windex}
if test -f $i
set -g __fish_whatis_path $i
break
end
end
#
# Convenience functions
#
@ -32,55 +22,6 @@ end
# without the description
#
#
# Find files that complete $argv[1], has the suffix $argv[2], and
# output them as completions with description $argv[3]
#
function __fish_complete_suffix -d "Complete using files"
set -- comp $argv[1]
set -- suff $argv[2]
set -- desc $argv[3]
set -- base (echo $comp |sed -e 's/\.[a-zA-Z0-9]*$//')
eval "set -- files $base*$suff"
if test $files[1]
printf "%s\t$desc\n" $files
end
#
# Also do directory completion, since there might be files
# with the correct suffix in a subdirectory
#
__fish_complete_directory $comp
end
#
# Find directories that complete $argv[1], output them as completions
# with description $argv[2] if defined, otherwise use 'Directory'
#
function __fish_complete_directory -d "Complete using directories"
set -- comp $argv[1]
set -- desc (_ Directory)
if test (count $argv) -gt 1
set desc $argv[2]
end
eval "set -- dirs "$comp"*/"
if test $dirs[1]
printf "%s\t$desc\n" $dirs
end
end
function __fish_complete_users -d "Print a list of local users, with the real user name as a description"
cat /etc/passwd | sed -e "s/^\([^:]*\):[^:]*:[^:]*:[^:]*:\([^:]*\):.*/\1\t\2/"
end
@ -101,42 +42,6 @@ function __fish_complete_command -d "Complete using all available commands"
printf "%s\n" (commandline -ct)(complete -C (commandline -ct))
end
function __fish_complete_subcommand -d "Complete subcommand"
set -l res ""
set -l had_cmd 0
set -l cmd (commandline -cop) (commandline -ct)
set -l skip_next 1
for i in $cmd
if test "$skip_next" = 1
set skip_next 0
continue
end
if test "$had_cmd" = 1
set res "$res $i"
else
if contains -- $i $argv
set skip_next 1
continue
end
switch $i
case '-*'
case '*'
set had_cmd 1
set res $i
end
end
end
printf "%s\n" (commandline -ct)(complete -C $res)
end
function __fish_print_hostnames -d "Print a list of known hostnames"
@ -166,59 +71,6 @@ function __fish_print_users -d "Print a list of local users"
cat /etc/passwd | cut -d : -f 1
end
function __fish_contains_opt -d "Checks if a specific option has been given in the current commandline"
set -l next_short
set -l short_opt
set -l long_opt
for i in $argv
if test $next_short
set next_short
set -- short_opt $short_opt $i
else
switch $i
case -s
set next_short 1
case '-*'
echo __fish_contains_opt: Unknown option $i
return 1
case '**'
set -- long_opt $long_opt $i
end
end
end
for i in $short_opt
if test -z $i
continue
end
if commandline -cpo | grep -- "^-"$i"\|^-[^-]*"$i >/dev/null
return 0
end
if commandline -ct | grep -- "^-"$i"\|^-[^-]*"$i >/dev/null
return 0
end
end
for i in $long_opt
if test -z $i
continue
end
if contains -- --$i (commandline -cpo)
return 0
end
end
return 1
end
#
# Completions for the shell and it's builtin commands and functions
#
@ -231,61 +83,6 @@ end
function __fish_print_packages
# apt-cache is much, much faster than rpm, and can do this in real
# time. We use it if available.
switch (commandline -tc)
case '-**'
return
end
#Get the word 'Package' in the current language
set -l package (_ Package)
if which apt-cache >/dev/null ^/dev/null
# Apply the following filters to output of apt-cache:
# 1) Remove package names with parentesis in them, since these seem to not correspond to actual packages as reported by rpm
# 2) Remove package names that are .so files, since these seem to not correspond to actual packages as reported by rpm
# 3) Remove path information such as /usr/bin/, as rpm packages do not have paths
apt-cache --no-generate pkgnames (commandline -tc)|grep -v \( |grep -v '\.so\(\.[0-9]\)*$'|sed -e 's/\/.*\///'|sed -e 's/$/\t'$package'/'
return
end
# Rpm is too slow for this job, so we set it up to do completions
# as a background job and cache the results.
if which rpm >/dev/null ^/dev/null
# If the cache is less than five minutes old, we do not recalculate it
set cache_file /tmp/.rpm-cache.$USER
if test -f $cache_file
cat $cache_file
set age (echo (date +%s) - (stat -c '%Y' $cache_file) | bc)
set max_age 250
if test $age -lt $max_age
return
end
end
# Remove package version information from output and pipe into cache file
rpm -qa >$cache_file |sed -e 's/-[^-]*-[^-]*$//' | sed -e 's/$/\t'$package'/' &
end
# This completes the package name from the portage tree.
# True for installing new packages. Function for printing
# installed on the system packages is in completions/emerge.fish
if which emerge >/dev/null ^/dev/null
emerge -s \^(commandline -tc) |grep "^*" |cut -d\ -f3 |cut -d/ -f2
return
end
end
function __fish_append -d "Internal completion function for appending string to the commandline"
set separator $argv[1]
set -e argv[1]
@ -293,35 +90,6 @@ function __fish_append -d "Internal completion function for appending string to
printf "%s\n" "$str"$argv "$str"(printf "%s\n" $argv|sed -e "s/\(\t\|\$\)/,\1/")
end
function __fish_gnu_complete -d "Wrapper for the complete builtin. Skips the long completions on non-GNU systems"
set is_gnu 0
# Check if we are using a gnu system
for i in (seq (count $argv))
switch $argv[$i]
case -g --is-gnu
set -e argv[$i]
set is_gnu 1
break
end
end
# Remove long option if not on a gnu system
if test $is_gnu = 0
for i in (seq (count $argv))
if test $argv[$i] = -l
set -e argv[$i]
set -e argv[$i]
break
end
end
end
complete $argv
end
function __fish_is_first_token -d 'Test if no non-switch argument has been specified yet'
set -- cmd (commandline -poc)
set -e -- cmd[1]

View file

@ -47,117 +47,6 @@ function contains -d "Test if a key is contained in a set of values"
end
#
# help should use 'open' to find a suitable browser, but only
# if there is a mime database _and_ DISPLAY is set, since the
# browser will most likely be graphical. Since most systems which
# have a mime databe also have the htmlview program, this is mostly a
# theoretical problem.
#
function help -d "Show help for the fish shell"
# Declare variables to set correct scope
set -l fish_browser
set -l fish_browser_bg
set -l h syntax completion editor job-control todo bugs history killring help
set h $h color prompt title variables builtin-overview changes expand
set h $h expand-variable expand-home expand-brace expand-wildcard
set -l help_topics $h expand-command-substitution expand-process
#
# Find a suitable browser for viewing the help pages. This is needed
# by the help function defined below.
#
set -l graphical_browsers htmlview x-www-browser firefox galeon mozilla konqueror epiphany opera netscape
set -l text_browsers htmlview www-browser links elinks lynx w3m
if test $BROWSER
# User has manualy set a preferred browser, so we respect that
set fish_browser $BROWSER
# If browser is known to be graphical, put into background
if contains -- $BROWSER $graphical_browsers
set fish_browser_bg 1
end
else
# Check for a text-based browser.
for i in $text_browsers
if which $i 2>/dev/null >/dev/null
set fish_browser $i
break
end
end
# If we are in a graphical environment, check if there is a graphical
# browser to use instead.
if test "$DISPLAY" -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \)
for i in $graphical_browsers
if which $i 2>/dev/null >/dev/null
set fish_browser $i
set fish_browser_bg 1
break
end
end
end
end
if test -z $fish_browser
printf (_ '%s: Could not find a web browser.\n') help
printf (_ 'Please set the variable $BROWSER to a suitable browser and try again\n\n')
return 1
end
set fish_help_item $argv[1]
switch "$fish_help_item"
case ""
set fish_help_page index.html
case "."
set fish_help_page "builtins.html\#source"
case difference
set fish_help_page difference.html
case globbing
set fish_help_page "index.html\#expand"
case (builtin -n)
set fish_help_page "builtins.html\#$fish_help_item"
case contains count dirh dirs help mimedb nextd open popd prevd pushd set_color tokenize psub umask type vared
set fish_help_page "commands.html\#$fish_help_item"
case $help_topics
set fish_help_page "index.html\#$fish_help_item"
case "*"
if which $fish_help_item >/dev/null ^/dev/null
man $fish_help_item
return
end
set fish_help_page "index.html"
end
if test $fish_browser_bg
eval $fish_browser file://$__fish_help_dir/$fish_help_page \&
else
eval $fish_browser file://$__fish_help_dir/$fish_help_page
end
end
#
# Make ls use colors if we are on a system that supports this
#
if ls --version 1>/dev/null 2>/dev/null
# This is GNU ls
function ls -d "List contents of directory"
command ls --color=auto --indicator-style=classify $argv
end
else
# BSD, OS X and a few more support colors through the -G switch instead
if ls / -G 1>/dev/null 2>/dev/null
function ls -d "List contents of directory"
command ls -G $argv
end
end
end
#
# These are very common and useful
@ -170,16 +59,6 @@ function la -d "List contents of directory using long format, showing hidden fil
ls -lha $argv
end
#
# This allows us to use 'open FILENAME' to open a given file in the default
# application for the file.
#
if not test (uname) = Darwin
function open -d "Open file in default application"
mimedb -l -- $argv
end
end
#
# Print the current working directory in a shortened form.This
@ -214,52 +93,6 @@ function pwd -d "Print working directory"
command pwd | sed -e 's|/private||' -e "s|^$HOME|~|"
end
#
# This is a neat function, stolen from zsh. It allows you to edit the
# value of a variable interactively.
#
function vared -d "Edit variable value"
if test (count $argv) = 1
switch $argv
case '-h' '--h' '--he' '--hel' '--help'
help vared
case '-*'
printf (_ "%s: Unknown option %s\n") vared $argv
case '*'
if test (count $$argv ) -lt 2
set init ''
if test $$argv
set -- init $$argv
end
set prompt 'set_color green; echo '$argv'; set_color normal; echo "> "'
read -p $prompt -c $init tmp
# If variable already exists, do not add any
# switches, so we don't change export rules. But
# if it does not exist, we make the variable
# global, so that it will not die when this
# function dies
if test $$argv
set -- $argv $tmp
else
set -g -- $argv $tmp
end
else
printf (_ '%s: %s is an array variable. Use %svared%s %s[n] to edit the n:th element of %s\n') $argv (set_color $fish_color_command) (set_color $fish_color_normal) vared $argv $argv
end
end
else
printf (_ '%s: Expected exactly one argument, got %s.\n\nSynopsis:\n\t%svared%s VARIABLE\n') vared (count $argv) (set_color $fish_color_command) (set_color $fish_color_normal)
end
end
#
# This function is used internally by the fish command completion code
#
@ -360,160 +193,6 @@ function cd -d "Change directory"
end
function __fish_move_last -d "Move the last element of a directory history from src to dest"
set -l src $argv[1]
set -l dest $argv[2]
set -l size_src (count $$src)
if test $size_src = 0
# Cannot make this step
printf (_ "Hit end of history...\n")
return 1
end
# Append current dir to the end of the destination
set -g (echo $dest) $$dest (command pwd)
set ssrc $$src
# Change dir to the last entry in the source dir-hist
builtin cd $ssrc[$size_src]
# Keep all but the last from the source dir-hist
set -e (echo $src)[$size_src]
# All ok, return success
return 0
end
function prevd -d "Move back in the directory history"
# Parse arguments
set -l show_hist 0
set -l times 1
for i in (seq (count $argv))
switch $argv[$i]
case '-l' --l --li --lis --list
set show_hist 1
continue
case '-*'
printf (_ "%s: Unknown option %s\n" ) prevd $argv[$i]
return 1
case '*'
if test $argv[$i] -ge 0 ^/dev/null
set times $argv[$i]
else
printf (_ "The number of positions to skip must be a non-negative integer\n")
return 1
end
continue
end
end
# Traverse history
set -l code 1
for i in (seq $times)
# Try one step backward
if __fish_move_last dirprev dirnext;
# We consider it a success if we were able to do at least 1 step
# (low expectations are the key to happiness ;)
set code 0
else
break
end
end
# Show history if needed
if test $show_hist = 1
dirh
end
# Set direction for 'cd -'
if test $code = 0 ^/dev/null
set -g __fish_cd_direction next
end
# All done
return $code
end
function nextd -d "Move forward in the directory history"
# Parse arguments
set -l show_hist 0
set -l times 1
for i in (seq (count $argv))
switch $argv[$i]
case '-l' --l --li --lis --list
set show_hist 1
continue
case '-*'
printf (_ "%s: Unknown option %s\n" ) nextd $argv[$i]
return 1
case '*'
if test $argv[$i] -ge 0 ^/dev/null
set times $argv[$i]
else
printf (_ "%s: The number of positions to skip must be a non-negative integer\n" ) nextd
return 1
end
continue
end
end
# Traverse history
set -l code 1
for i in (seq $times)
# Try one step backward
if __fish_move_last dirnext dirprev;
# We consider it a success if we were able to do at least 1 step
# (low expectations are the key to happiness ;)
set code 0
else
break
end
end
# Show history if needed
if test $show_hist = 1
dirh
end
# Set direction for 'cd -'
if test $code = 0 ^/dev/null
set -g __fish_cd_direction prev
end
# All done
return $code
end
function dirh -d "Print the current directory history (the back- and fwd- lists)"
# Avoid set comment
set -l current (command pwd)
set -l separator " "
set -l line_len (echo (count $dirprev) + (echo $dirprev $current $dirnext | wc -m) | bc)
if test $line_len -gt $COLUMNS
# Print one entry per line if history is long
set separator "\n"
end
for i in $dirprev
echo -n -e $i$separator
end
set_color $fish_color_history_current
echo -n -e $current$separator
set_color normal
for i in (seq (echo (count $dirnext)) -1 1)
echo -n -e $dirnext[$i]$separator
end
echo
end
function __bold -d "Print argument in bold"
set_color --bold
@ -522,536 +201,6 @@ function __bold -d "Print argument in bold"
end
function __trap_translate_signal
set upper (echo $argv[1]|tr a-z A-Z)
if expr $upper : 'SIG.*' >/dev/null
echo $upper | cut -c 4-
else
echo $upper
end
end
function __trap_switch
switch $argv[1]
case EXIT
echo --on-exit %self
case '*'
echo --on-signal $argv[1]
end
end
function trap -d 'Perform an action when the shell recives a signal'
set -l mode
set -l cmd
set -l sig
set -l shortopt
set -l longopt
set -l shortopt -o lph
set -l longopt
if not getopt -T >/dev/null
set longopt -l print,help,list-signals
end
if not getopt -n type -Q $shortopt $longopt -- $argv
return 1
end
set -l tmp (getopt $shortopt $longopt -- $argv)
eval set opt $tmp
while count $opt >/dev/null
switch $opt[1]
case -h --help
help trap
return 0
case -p --print
set mode print
case -l --list-signals
set mode list
case --
set -e opt[1]
break
end
set -e opt[1]
end
if not count $mode >/dev/null
switch (count $opt)
case 0
set mode print
case 1
set mode clear
case '*'
if test opt[1] = -
set -e opt[1]
set mode clear
else
set mode set
end
end
end
switch $mode
case clear
for i in $opt
set -- sig (__trap_translate_signal $i)
if test $sig
functions -e __trap_handler_$sig
end
end
case set
set -l cmd $opt[1]
set -e opt[1]
for i in $opt
set -l -- sig (__trap_translate_signal $i)
set -- sw (__trap_switch $sig)
if test $sig
eval "function __trap_handler_$sig $sw; $cmd; end"
else
return 1
end
end
case print
set -l names
if count $opt >/dev/null
set -- names $opt
else
set -- names (functions -na|grep "^__trap_handler_"|sed -e 's/__trap_handler_//' )
end
for i in $names
set -- sig (__trap_translate_signal $i)
if test sig
functions __trap_handler_$i
else
return 1
end
end
case list
kill -l
end
end
function type -d "Print the type of a command"
# Initialize
set -l status 1
set -l mode normal
set -l selection all
#
# Get options
#
set -l shortopt -o tpPafh
set -l longopt
if not getopt -T >/dev/null
set longopt -l type,path,force-path,all,no-functions,help
end
if not getopt -n type -Q $shortopt $longopt -- $argv
return 1
end
set -l tmp (getopt $shortopt $longopt -- $argv)
set -l opt
eval set opt $tmp
for i in $opt
switch $i
case -t --type
set mode type
case -p --path
set mode path
case -P --force-path
set mode path
set selection files
case -a --all
set selection multi
case -f --no-functions
set selection files
case -h --help
help type
return 0
case --
break
end
end
# Check all possible types for the remaining arguments
for i in $argv
switch $i
case '-*'
continue
end
# Found will be set to 1 if a match is found
set found 0
if test $selection != files
if contains -- $i (functions -na)
set status 0
set found 1
switch $mode
case normal
printf (_ '%s is a function with definition\n') $i
functions $i
case type
printf (_ 'function\n')
case path
echo
end
if test $selection != multi
continue
end
end
if contains -- $i (builtin -n)
set status 0
set found 1
switch $mode
case normal
printf (_ '%s is a builtin\n') $i
case type
printf (_ 'builtin\n')
case path
echo
end
if test $selection != multi
continue
end
end
end
if which $i ^/dev/null >/dev/null
set status 0
set found 1
switch $mode
case normal
printf (_ '%s is %s\n') $i (which $i)
case type
printf (_ 'file\n')
case path
which $i
end
if test $selection != multi
continue
end
end
if test $found = 0
printf (_ "%s: Could not find '%s'") type $i
end
end
return $status
end
function __fish_umask_parse -d "Parses a file permission specification as into an octal version"
# Test if already a valid octal mask, and pad it with zeros
if echo $argv | grep -E '^(0|)[0-7]{1,3}$' >/dev/null
for i in (seq (echo 5-(echo $argv|wc -c)|bc)); set argv 0$argv; end
echo $argv
else
# Test if argument really is a valid symbolic mask
if not echo $argv | grep -E '^(((u|g|o|a|)(=|\+|-)|)(r|w|x)*)(,(((u|g|o|a|)(=|\+|-)|)(r|w|x)*))*$' >/dev/null
printf (_ "%s: Invalid mask '%s'\n") umask $argv >&2
return 1
end
set -l implicit_all
# Insert inverted umask into res variable
set -l mode
set -l val
set -l tmp $umask
set -l res
for i in 1 2 3
set tmp (echo $tmp|cut -c 2-)
set res[$i] (echo 7-(echo $tmp|cut -c 1)|bc)
end
set -l el (echo $argv|tr , \n)
for i in $el
switch $i
case 'u*'
set idx 1
set i (echo $i| cut -c 2-)
case 'g*'
set idx 2
set i (echo $i| cut -c 2-)
case 'o*'
set idx 3
set i (echo $i| cut -c 2-)
case 'a*'
set idx 1 2 3
set i (echo $i| cut -c 2-)
case '*'
set implicit_all 1
set idx 1 2 3
end
switch $i
case '=*'
set mode set
set i (echo $i| cut -c 2-)
case '+*'
set mode add
set i (echo $i| cut -c 2-)
case '-*'
set mode remove
set i (echo $i| cut -c 2-)
case '*'
if not count $implicit_all >/dev/null
printf (_ "%s: Invalid mask %s\n") umask $argv >&2
return
end
set mode set
end
if not echo $perm|grep -E '^(r|w|x)*$' >/dev/null
printf (_ "%s: Invalid mask %s\n") umask $argv >&2
return
end
set val 0
if echo $i |grep 'r' >/dev/null
set val 4
end
if echo $i |grep 'w' >/dev/null
set val (echo $val + 2|bc)
end
if echo $i |grep 'x' >/dev/null
set val (echo $val + 1|bc)
end
for j in $idx
switch $mode
case set
set res[$j] $val
case add
set res[$j] (perl -e 'print( ( '$res[$j]'|'$val[$j]' )."\n" )')
case remove
set res[$j] (perl -e 'print( ( (7-'$res[$j]')&'$val[$j]' )."\n" )')
end
end
end
for i in 1 2 3
set res[$i] (echo 7-$res[$i]|bc)
end
echo 0$res[1]$res[2]$res[3]
end
end
function __fish_umask_print_symbolic
set -l res ""
set -l letter a u g o
for i in 2 3 4
set res $res,$letter[$i]=
set val (echo $umask|cut -c $i)
if contains $val 0 1 2 3
set res {$res}r
end
if contains $val 0 1 4 5
set res {$res}w
end
if contains $val 0 2 4 6
set res {$res}x
end
end
echo $res|cut -c 2-
end
function umask -d "Set default file permission mask"
set -l as_command 0
set -l symbolic 0
set -l shortopt -o pSh
set -l longopt
if not getopt -T >/dev/null
set longopt -l as-command,symbolic,help
end
if not getopt -n umask -Q $shortopt $longopt -- $argv
return 1
end
set -l tmp (getopt $shortopt $longopt -- $argv)
eval set opt $tmp
while count $opt >/dev/null
switch $opt[1]
case -h --help
help umask
return 0
case -p --as-command
set as_command 1
case -S --symbolic
set symbolic 1
case --
set -e opt[1]
break
end
set -e opt[1]
end
switch (count $opt)
case 0
if not set -q umask
set -g umask 113
end
if test $as_command -eq 1
echo umask $umask
else
if test $symbolic -eq 1
__fish_umask_print_symbolic $umask
else
echo $umask
end
end
case 1
set -l parsed (__fish_umask_parse $opt)
if test (count $parsed) -eq 1
set -g umask $parsed
return 0
end
return 1
case '*'
printf (_ '%s: Too many arguments\n') umask >&2
end
end
function psub -d "Read from stdin into a file and output the filename. Remove the file when the command that calles psub exits."
set -l filename
set -l funcname
if count $argv >/dev/null
switch $argv[1]
case '-h*' --h --he --hel --help
help psub
return 0
case '*'
printf (_ "%s: Unknown argument '%s'\n") psub $argv[1]
return 1
end
end
if not status --is-command-substitution
echo psub: Not inside of command substitution >&2
return
end
# Find unique file name for writing output to
while true
set filename /tmp/.psub.(echo %self).(random);
if not test -e $filename
break;
end
end
# Write output to pipe. This needs to be done in the background so
# that the command substitution exits without needing to wait for
# all the commands to exit
mkfifo $filename
cat >$filename &
# Write filename to stdout
echo $filename
# Find unique function name
while true
set funcname __fish_psub_(random);
if not functions $funcname >/dev/null ^/dev/null
break;
end
end
# Make sure we erase file when caller exits
eval function $funcname --on-job-exit caller\; rm $filename\; functions -e $funcname\; end
end
function prevd-or-backward-word --key-binding
if test -z (commandline)
prevd

View file

@ -0,0 +1,22 @@
#
# Find directories that complete $argv[1], output them as completions
# with description $argv[2] if defined, otherwise use 'Directory'
#
function __fish_complete_directory -d "Complete using directories"
set -- comp $argv[1]
set -- desc (_ Directory)
if test (count $argv) -gt 1
set desc $argv[2]
end
eval "set -- dirs "$comp"*/"
if test $dirs[1]
printf "%s\t$desc\n" $dirs
end
end

View file

@ -0,0 +1,36 @@
function __fish_complete_subcommand -d "Complete subcommand"
set -l res ""
set -l had_cmd 0
set -l cmd (commandline -cop) (commandline -ct)
set -l skip_next 1
for i in $cmd
if test "$skip_next" = 1
set skip_next 0
continue
end
if test "$had_cmd" = 1
set res "$res $i"
else
if contains -- $i $argv
set skip_next 1
continue
end
switch $i
case '-*'
case '*'
set had_cmd 1
set res $i
end
end
end
printf "%s\n" (commandline -ct)(complete -C $res)
end

View file

@ -0,0 +1,26 @@
#
# Find files that complete $argv[1], has the suffix $argv[2], and
# output them as completions with description $argv[3]
#
function __fish_complete_suffix -d "Complete using files"
set -- comp $argv[1]
set -- suff $argv[2]
set -- desc $argv[3]
set -- base (echo $comp |sed -e 's/\.[a-zA-Z0-9]*$//')
eval "set -- files $base*$suff"
if test $files[1]
printf "%s\t$desc\n" $files
end
#
# Also do directory completion, since there might be files
# with the correct suffix in a subdirectory
#
__fish_complete_directory $comp
end

View file

@ -0,0 +1,53 @@
function __fish_contains_opt -d "Checks if a specific option has been given in the current commandline"
set -l next_short
set -l short_opt
set -l long_opt
for i in $argv
if test $next_short
set next_short
set -- short_opt $short_opt $i
else
switch $i
case -s
set next_short 1
case '-*'
echo __fish_contains_opt: Unknown option $i
return 1
case '**'
set -- long_opt $long_opt $i
end
end
end
for i in $short_opt
if test -z $i
continue
end
if commandline -cpo | grep -- "^-"$i"\|^-[^-]*"$i >/dev/null
return 0
end
if commandline -ct | grep -- "^-"$i"\|^-[^-]*"$i >/dev/null
return 0
end
end
for i in $long_opt
if test -z $i
continue
end
if contains -- --$i (commandline -cpo)
return 0
end
end
return 1
end

View file

@ -0,0 +1,29 @@
function __fish_gnu_complete -d "Wrapper for the complete builtin. Skips the long completions on non-GNU systems"
set is_gnu 0
# Check if we are using a gnu system
for i in (seq (count $argv))
switch $argv[$i]
case -g --is-gnu
set -e argv[$i]
set is_gnu 1
break
end
end
# Remove long option if not on a gnu system
if test $is_gnu = 0
for i in (seq (count $argv))
if test $argv[$i] = -l
set -e argv[$i]
set -e argv[$i]
break
end
end
end
complete $argv
end

View file

@ -0,0 +1,27 @@
function __fish_move_last -d "Move the last element of a directory history from src to dest"
set -l src $argv[1]
set -l dest $argv[2]
set -l size_src (count $$src)
if test $size_src = 0
# Cannot make this step
printf (_ "Hit end of history...\n")
return 1
end
# Append current dir to the end of the destination
set -g (echo $dest) $$dest (command pwd)
set ssrc $$src
# Change dir to the last entry in the source dir-hist
builtin cd $ssrc[$size_src]
# Keep all but the last from the source dir-hist
set -e (echo $src)[$size_src]
# All ok, return success
return 0
end

View file

@ -0,0 +1,55 @@
function __fish_print_packages
# apt-cache is much, much faster than rpm, and can do this in real
# time. We use it if available.
switch (commandline -tc)
case '-**'
return
end
#Get the word 'Package' in the current language
set -l package (_ Package)
if which apt-cache >/dev/null ^/dev/null
# Apply the following filters to output of apt-cache:
# 1) Remove package names with parentesis in them, since these seem to not correspond to actual packages as reported by rpm
# 2) Remove package names that are .so files, since these seem to not correspond to actual packages as reported by rpm
# 3) Remove path information such as /usr/bin/, as rpm packages do not have paths
apt-cache --no-generate pkgnames (commandline -tc)|grep -v \( |grep -v '\.so\(\.[0-9]\)*$'|sed -e 's/\/.*\///'|sed -e 's/$/\t'$package'/'
return
end
# Rpm is too slow for this job, so we set it up to do completions
# as a background job and cache the results.
if which rpm >/dev/null ^/dev/null
# If the cache is less than five minutes old, we do not recalculate it
set cache_file /tmp/.rpm-cache.$USER
if test -f $cache_file
cat $cache_file
set age (echo (date +%s) - (stat -c '%Y' $cache_file) | bc)
set max_age 250
if test $age -lt $max_age
return
end
end
# Remove package version information from output and pipe into cache file
rpm -qa >$cache_file |sed -e 's/-[^-]*-[^-]*$//' | sed -e 's/$/\t'$package'/' &
end
# This completes the package name from the portage tree.
# True for installing new packages. Function for printing
# installed on the system packages is in completions/emerge.fish
if which emerge >/dev/null ^/dev/null
emerge -s \^(commandline -tc) |grep "^*" |cut -d\ -f3 |cut -d/ -f2
return
end
end

26
init/functions/dirh.fish Normal file
View file

@ -0,0 +1,26 @@
function dirh -d "Print the current directory history (the back- and fwd- lists)"
# Avoid set comment
set -l current (command pwd)
set -l separator " "
set -l line_len (echo (count $dirprev) + (echo $dirprev $current $dirnext | wc -m) | bc)
if test $line_len -gt $COLUMNS
# Print one entry per line if history is long
set separator "\n"
end
for i in $dirprev
echo -n -e $i$separator
end
set_color $fish_color_history_current
echo -n -e $current$separator
set_color normal
for i in (seq (echo (count $dirnext)) -1 1)
echo -n -e $dirnext[$i]$separator
end
echo
end

94
init/functions/help.fish Normal file
View file

@ -0,0 +1,94 @@
#
# help should use 'open' to find a suitable browser, but only
# if there is a mime database _and_ DISPLAY is set, since the
# browser will most likely be graphical. Since most systems which
# have a mime databe also have the htmlview program, this is mostly a
# theoretical problem.
#
function help -d "Show help for the fish shell"
# Declare variables to set correct scope
set -l fish_browser
set -l fish_browser_bg
set -l h syntax completion editor job-control todo bugs history killring help
set h $h color prompt title variables builtin-overview changes expand
set h $h expand-variable expand-home expand-brace expand-wildcard
set -l help_topics $h expand-command-substitution expand-process
#
# Find a suitable browser for viewing the help pages. This is needed
# by the help function defined below.
#
set -l graphical_browsers htmlview x-www-browser firefox galeon mozilla konqueror epiphany opera netscape
set -l text_browsers htmlview www-browser links elinks lynx w3m
if test $BROWSER
# User has manualy set a preferred browser, so we respect that
set fish_browser $BROWSER
# If browser is known to be graphical, put into background
if contains -- $BROWSER $graphical_browsers
set fish_browser_bg 1
end
else
# Check for a text-based browser.
for i in $text_browsers
if which $i 2>/dev/null >/dev/null
set fish_browser $i
break
end
end
# If we are in a graphical environment, check if there is a graphical
# browser to use instead.
if test "$DISPLAY" -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \)
for i in $graphical_browsers
if which $i 2>/dev/null >/dev/null
set fish_browser $i
set fish_browser_bg 1
break
end
end
end
end
if test -z $fish_browser
printf (_ '%s: Could not find a web browser.\n') help
printf (_ 'Please set the variable $BROWSER to a suitable browser and try again\n\n')
return 1
end
set fish_help_item $argv[1]
switch "$fish_help_item"
case ""
set fish_help_page index.html
case "."
set fish_help_page "builtins.html\#source"
case difference
set fish_help_page difference.html
case globbing
set fish_help_page "index.html\#expand"
case (builtin -n)
set fish_help_page "builtins.html\#$fish_help_item"
case contains count dirh dirs help mimedb nextd open popd prevd pushd set_color tokenize psub umask type vared
set fish_help_page "commands.html\#$fish_help_item"
case $help_topics
set fish_help_page "index.html\#$fish_help_item"
case "*"
if which $fish_help_item >/dev/null ^/dev/null
man $fish_help_item
return
end
set fish_help_page "index.html"
end
if test $fish_browser_bg
eval $fish_browser file://$__fish_help_dir/$fish_help_page \&
else
eval $fish_browser file://$__fish_help_dir/$fish_help_page
end
end

18
init/functions/ls.fish Normal file
View file

@ -0,0 +1,18 @@
#
# Make ls use colors if we are on a system that supports this
#
if ls --version 1>/dev/null 2>/dev/null
# This is GNU ls
function ls -d "List contents of directory"
command ls --color=auto --indicator-style=classify $argv
end
else
# BSD, OS X and a few more support colors through the -G switch instead
if ls / -G 1>/dev/null 2>/dev/null
function ls -d "List contents of directory"
command ls -G $argv
end
end
end

50
init/functions/nextd.fish Normal file
View file

@ -0,0 +1,50 @@
function nextd -d "Move forward in the directory history"
# Parse arguments
set -l show_hist 0
set -l times 1
for i in (seq (count $argv))
switch $argv[$i]
case '-l' --l --li --lis --list
set show_hist 1
continue
case '-*'
printf (_ "%s: Unknown option %s\n" ) nextd $argv[$i]
return 1
case '*'
if test $argv[$i] -ge 0 ^/dev/null
set times $argv[$i]
else
printf (_ "%s: The number of positions to skip must be a non-negative integer\n" ) nextd
return 1
end
continue
end
end
# Traverse history
set -l code 1
for i in (seq $times)
# Try one step backward
if __fish_move_last dirnext dirprev;
# We consider it a success if we were able to do at least 1 step
# (low expectations are the key to happiness ;)
set code 0
else
break
end
end
# Show history if needed
if test $show_hist = 1
dirh
end
# Set direction for 'cd -'
if test $code = 0 ^/dev/null
set -g __fish_cd_direction prev
end
# All done
return $code
end

12
init/functions/open.fish Normal file
View file

@ -0,0 +1,12 @@
#
# This allows us to use 'open FILENAME' to open a given file in the default
# application for the file.
#
if not test (uname) = Darwin
function open -d "Open file in default application"
mimedb -l -- $argv
end
end

51
init/functions/prevd.fish Normal file
View file

@ -0,0 +1,51 @@
function prevd -d "Move back in the directory history"
# Parse arguments
set -l show_hist 0
set -l times 1
for i in (seq (count $argv))
switch $argv[$i]
case '-l' --l --li --lis --list
set show_hist 1
continue
case '-*'
printf (_ "%s: Unknown option %s\n" ) prevd $argv[$i]
return 1
case '*'
if test $argv[$i] -ge 0 ^/dev/null
set times $argv[$i]
else
printf (_ "The number of positions to skip must be a non-negative integer\n")
return 1
end
continue
end
end
# Traverse history
set -l code 1
for i in (seq $times)
# Try one step backward
if __fish_move_last dirprev dirnext;
# We consider it a success if we were able to do at least 1 step
# (low expectations are the key to happiness ;)
set code 0
else
break
end
end
# Show history if needed
if test $show_hist = 1
dirh
end
# Set direction for 'cd -'
if test $code = 0 ^/dev/null
set -g __fish_cd_direction next
end
# All done
return $code
end

54
init/functions/psub.fish Normal file
View file

@ -0,0 +1,54 @@
function psub -d "Read from stdin into a file and output the filename. Remove the file when the command that calles psub exits."
set -l filename
set -l funcname
if count $argv >/dev/null
switch $argv[1]
case '-h*' --h --he --hel --help
help psub
return 0
case '*'
printf (_ "%s: Unknown argument '%s'\n") psub $argv[1]
return 1
end
end
if not status --is-command-substitution
echo psub: Not inside of command substitution >&2
return
end
# Find unique file name for writing output to
while true
set filename /tmp/.psub.(echo %self).(random);
if not test -e $filename
break;
end
end
# Write output to pipe. This needs to be done in the background so
# that the command substitution exits without needing to wait for
# all the commands to exit
mkfifo $filename
cat >$filename &
# Write filename to stdout
echo $filename
# Find unique function name
while true
set funcname __fish_psub_(random);
if not functions $funcname >/dev/null ^/dev/null
break;
end
end
# Make sure we erase file when caller exits
eval function $funcname --on-job-exit caller\; rm $filename\; functions -e $funcname\; end
end

136
init/functions/trap.fish Normal file
View file

@ -0,0 +1,136 @@
function __trap_translate_signal
set upper (echo $argv[1]|tr a-z A-Z)
if expr $upper : 'SIG.*' >/dev/null
echo $upper | cut -c 4-
else
echo $upper
end
end
function __trap_switch
switch $argv[1]
case EXIT
echo --on-exit %self
case '*'
echo --on-signal $argv[1]
end
end
function trap -d 'Perform an action when the shell recives a signal'
set -l mode
set -l cmd
set -l sig
set -l shortopt
set -l longopt
set -l shortopt -o lph
set -l longopt
if not getopt -T >/dev/null
set longopt -l print,help,list-signals
end
if not getopt -n type -Q $shortopt $longopt -- $argv
return 1
end
set -l tmp (getopt $shortopt $longopt -- $argv)
eval set opt $tmp
while count $opt >/dev/null
switch $opt[1]
case -h --help
help trap
return 0
case -p --print
set mode print
case -l --list-signals
set mode list
case --
set -e opt[1]
break
end
set -e opt[1]
end
if not count $mode >/dev/null
switch (count $opt)
case 0
set mode print
case 1
set mode clear
case '*'
if test opt[1] = -
set -e opt[1]
set mode clear
else
set mode set
end
end
end
switch $mode
case clear
for i in $opt
set -- sig (__trap_translate_signal $i)
if test $sig
functions -e __trap_handler_$sig
end
end
case set
set -l cmd $opt[1]
set -e opt[1]
for i in $opt
set -l -- sig (__trap_translate_signal $i)
set -- sw (__trap_switch $sig)
if test $sig
eval "function __trap_handler_$sig $sw; $cmd; end"
else
return 1
end
end
case print
set -l names
if count $opt >/dev/null
set -- names $opt
else
set -- names (functions -na|grep "^__trap_handler_"|sed -e 's/__trap_handler_//' )
end
for i in $names
set -- sig (__trap_translate_signal $i)
if test sig
functions __trap_handler_$i
else
return 1
end
end
case list
kill -l
end
end

134
init/functions/type.fish Normal file
View file

@ -0,0 +1,134 @@
function type -d "Print the type of a command"
# Initialize
set -l status 1
set -l mode normal
set -l selection all
#
# Get options
#
set -l shortopt -o tpPafh
set -l longopt
if not getopt -T >/dev/null
set longopt -l type,path,force-path,all,no-functions,help
end
if not getopt -n type -Q $shortopt $longopt -- $argv
return 1
end
set -l tmp (getopt $shortopt $longopt -- $argv)
set -l opt
eval set opt $tmp
for i in $opt
switch $i
case -t --type
set mode type
case -p --path
set mode path
case -P --force-path
set mode path
set selection files
case -a --all
set selection multi
case -f --no-functions
set selection files
case -h --help
help type
return 0
case --
break
end
end
# Check all possible types for the remaining arguments
for i in $argv
switch $i
case '-*'
continue
end
# Found will be set to 1 if a match is found
set found 0
if test $selection != files
if contains -- $i (functions -na)
set status 0
set found 1
switch $mode
case normal
printf (_ '%s is a function with definition\n') $i
functions $i
case type
printf (_ 'function\n')
case path
echo
end
if test $selection != multi
continue
end
end
if contains -- $i (builtin -n)
set status 0
set found 1
switch $mode
case normal
printf (_ '%s is a builtin\n') $i
case type
printf (_ 'builtin\n')
case path
echo
end
if test $selection != multi
continue
end
end
end
if which $i ^/dev/null >/dev/null
set status 0
set found 1
switch $mode
case normal
printf (_ '%s is %s\n') $i (which $i)
case type
printf (_ 'file\n')
case path
which $i
end
if test $selection != multi
continue
end
end
if test $found = 0
printf (_ "%s: Could not find '%s'") type $i
end
end
return $status
end

206
init/functions/umask.fish Normal file
View file

@ -0,0 +1,206 @@
function __fish_umask_parse -d "Parses a file permission specification as into an octal version"
# Test if already a valid octal mask, and pad it with zeros
if echo $argv | grep -E '^(0|)[0-7]{1,3}$' >/dev/null
for i in (seq (echo 5-(echo $argv|wc -c)|bc)); set argv 0$argv; end
echo $argv
else
# Test if argument really is a valid symbolic mask
if not echo $argv | grep -E '^(((u|g|o|a|)(=|\+|-)|)(r|w|x)*)(,(((u|g|o|a|)(=|\+|-)|)(r|w|x)*))*$' >/dev/null
printf (_ "%s: Invalid mask '%s'\n") umask $argv >&2
return 1
end
set -l implicit_all
# Insert inverted umask into res variable
set -l mode
set -l val
set -l tmp $umask
set -l res
for i in 1 2 3
set tmp (echo $tmp|cut -c 2-)
set res[$i] (echo 7-(echo $tmp|cut -c 1)|bc)
end
set -l el (echo $argv|tr , \n)
for i in $el
switch $i
case 'u*'
set idx 1
set i (echo $i| cut -c 2-)
case 'g*'
set idx 2
set i (echo $i| cut -c 2-)
case 'o*'
set idx 3
set i (echo $i| cut -c 2-)
case 'a*'
set idx 1 2 3
set i (echo $i| cut -c 2-)
case '*'
set implicit_all 1
set idx 1 2 3
end
switch $i
case '=*'
set mode set
set i (echo $i| cut -c 2-)
case '+*'
set mode add
set i (echo $i| cut -c 2-)
case '-*'
set mode remove
set i (echo $i| cut -c 2-)
case '*'
if not count $implicit_all >/dev/null
printf (_ "%s: Invalid mask '%s'\n") umask $argv >&2
return
end
set mode set
end
if not echo $perm|grep -E '^(r|w|x)*$' >/dev/null
printf (_ "%s: Invalid mask '%s'\n") umask $argv >&2
return
end
set val 0
if echo $i |grep 'r' >/dev/null
set val 4
end
if echo $i |grep 'w' >/dev/null
set val (echo $val + 2|bc)
end
if echo $i |grep 'x' >/dev/null
set val (echo $val + 1|bc)
end
for j in $idx
switch $mode
case set
set res[$j] $val
case add
set res[$j] (perl -e 'print( ( '$res[$j]'|'$val[$j]' )."\n" )')
case remove
set res[$j] (perl -e 'print( ( (7-'$res[$j]')&'$val[$j]' )."\n" )')
end
end
end
for i in 1 2 3
set res[$i] (echo 7-$res[$i]|bc)
end
echo 0$res[1]$res[2]$res[3]
end
end
function __fish_umask_print_symbolic
set -l res ""
set -l letter a u g o
for i in 2 3 4
set res $res,$letter[$i]=
set val (echo $umask|cut -c $i)
if contains $val 0 1 2 3
set res {$res}r
end
if contains $val 0 1 4 5
set res {$res}w
end
if contains $val 0 2 4 6
set res {$res}x
end
end
echo $res|cut -c 2-
end
function umask -d "Set default file permission mask"
set -l as_command 0
set -l symbolic 0
set -l shortopt -o pSh
set -l longopt
if not getopt -T >/dev/null
set longopt -l as-command,symbolic,help
end
if not getopt -n umask -Q $shortopt $longopt -- $argv
return 1
end
set -l tmp (getopt $shortopt $longopt -- $argv)
eval set opt $tmp
while count $opt >/dev/null
switch $opt[1]
case -h --help
help umask
return 0
case -p --as-command
set as_command 1
case -S --symbolic
set symbolic 1
case --
set -e opt[1]
break
end
set -e opt[1]
end
switch (count $opt)
case 0
if not set -q umask
set -g umask 113
end
if test $as_command -eq 1
echo umask $umask
else
if test $symbolic -eq 1
__fish_umask_print_symbolic $umask
else
echo $umask
end
end
case 1
set -l parsed (__fish_umask_parse $opt)
if test (count $parsed) -eq 1
set -g umask $parsed
return 0
end
return 1
case '*'
printf (_ '%s: Too many arguments\n') umask >&2
end
end

47
init/functions/vared.fish Normal file
View file

@ -0,0 +1,47 @@
#
# This is a neat function, stolen from zsh. It allows you to edit the
# value of a variable interactively.
#
function vared -d "Edit variable value"
if test (count $argv) = 1
switch $argv
case '-h' '--h' '--he' '--hel' '--help'
help vared
case '-*'
printf (_ "%s: Unknown option %s\n") vared $argv
case '*'
if test (count $$argv ) -lt 2
set init ''
if test $$argv
set -- init $$argv
end
set prompt 'set_color green; echo '$argv'; set_color normal; echo "> "'
read -p $prompt -c $init tmp
# If variable already exists, do not add any
# switches, so we don't change export rules. But
# if it does not exist, we make the variable
# global, so that it will not die when this
# function dies
if test $$argv
set -- $argv $tmp
else
set -g -- $argv $tmp
end
else
printf (_ '%s: %s is an array variable. Use %svared%s %s[n] to edit the n:th element of %s\n') $argv (set_color $fish_color_command) (set_color $fish_color_normal) vared $argv $argv
end
end
else
printf (_ '%s: Expected exactly one argument, got %s.\n\nSynopsis:\n\t%svared%s VARIABLE\n') vared (count $argv) (set_color $fish_color_command) (set_color $fish_color_normal)
end
end

2
main.c
View file

@ -220,6 +220,7 @@ int main( int argc, char **argv )
builtin_init();
function_init();
env_init();
parse_util_init();
complete_init();
reader_init();
@ -303,6 +304,7 @@ int main( int argc, char **argv )
wutil_destroy();
common_destroy();
exec_destroy();
parse_util_destroy();
event_destroy();
output_destroy();
translate_destroy();

View file

@ -13,6 +13,7 @@
#include <wchar.h>
#include <time.h>
#include <assert.h>
#include "util.h"
@ -20,6 +21,14 @@
#include "common.h"
#include "tokenizer.h"
#include "parse_util.h"
#include "expand.h"
#include "intern.h"
#include "exec.h"
/**
Set of files which have been autoloaded
*/
static hash_table_t *loaded=0;
int parse_util_lineno( const wchar_t *str, int len )
{
@ -419,4 +428,151 @@ void parse_util_token_extent( const wchar_t *buff,
}
int parse_util_load( const wchar_t *cmd,
const wchar_t *path_var,
void (*on_load)(const wchar_t *cmd),
int reload )
{
array_list_t path_list;
int i;
string_buffer_t path;
time_t *tm;
int reloaded = 0;
/*
Do we know where to look
*/
if( !path_var )
return 0;
if( !loaded )
{
loaded = malloc( sizeof( hash_table_t ) );
if( !loaded )
{
die_mem();
}
hash_init( loaded, &hash_wcs_func, &hash_wcs_cmp );
}
/*
Get modification time of file
*/
tm = (time_t *)hash_get( loaded, cmd );
/*
Did we just check this?
*/
if( tm )
if(tm[1]-time(0)<=1)
return 0;
/*
Return if already loaded and we are skipping reloading
*/
if( !reload && tm )
return 0;
debug( 1, L"WOO %ls", cmd );
al_init( &path_list );
sb_init( &path );
expand_variable_array( path_var, &path_list );
/*
Iterate over path searching for suitable completion files
*/
for( i=0; i<al_get_count( &path_list ); i++ )
{
struct stat buf;
wchar_t *next = (wchar_t *)al_get( &path_list, i );
sb_clear( &path );
sb_append2( &path, next, L"/", cmd, L".fish", (void *)0 );
if( (wstat( (wchar_t *)path.buff, &buf )== 0) &&
(waccess( (wchar_t *)path.buff, R_OK ) == 0) )
{
if( !tm || (*tm != buf.st_mtime ) )
{
wchar_t *esc = escape( (wchar_t *)path.buff, 1 );
wchar_t *src_cmd = wcsdupcat( L". ", esc );
if( !tm )
{
tm = malloc(sizeof(time_t)*2);
if( !tm )
die_mem();
}
tm[0] = buf.st_mtime;
tm[1] = time(0);
hash_put( loaded,
intern( cmd ),
tm );
free( esc );
on_load(cmd );
/*
Source the completion file for the specified completion
*/
exec_subshell( src_cmd, 0 );
free(src_cmd);
reloaded = 1;
break;
}
}
}
/*
If no file was found we insert the current time. Later we only
research if the current time is at least five seconds later.
This way, the files won't be searched over and over again.
*/
if( !tm )
{
tm = malloc(sizeof(time_t)*2);
if( !tm )
die_mem();
tm[0] = 0;
tm[1] = time(0);
hash_put( loaded, intern( cmd ), tm );
}
sb_destroy( &path );
al_foreach( &path_list, (void (*)(const void *))&free );
al_destroy( &path_list );
return reloaded;
}
void parse_util_init()
{
}
/**
Free hash value, but not hash key
*/
static void clear_hash_value( const void *key, const void *data )
{
free( (void *)data );
}
void parse_util_destroy()
{
if( loaded )
{
hash_foreach( loaded,
&clear_hash_value );
hash_destroy( loaded );
free( loaded );
loaded = 0;
}
}

View file

@ -49,5 +49,16 @@ void parse_util_token_extent( const wchar_t *buff,
int parse_util_lineno( const wchar_t *str, int len );
int parse_util_load( const wchar_t *cmd,
const wchar_t *path_var,
void (*on_load)(const wchar_t *cmd),
int reload );
void parse_util_init();
void parse_util_destroy();
#endif

View file

@ -1856,7 +1856,7 @@ static int parse_job( process_t *p,
continue;
}
if( use_function)
if( use_function && !current_block->skip )
{
int nxt_forbidden;
wchar_t *forbid;