From 73a9c8bcb8d3d8db967fcc5cc9dd5e8db645400f Mon Sep 17 00:00:00 2001 From: axel Date: Wed, 8 Feb 2006 19:20:05 +1000 Subject: [PATCH] Autoloaded functions darcs-hash:20060208092005-ac50b-8e784f79a4e158c8c15b553fad85002dccc7bd03.gz --- Makefile.in | 12 +- common.c | 1 + complete.c | 137 +-- complete.h | 2 +- fish.spec.in | 2 + function.c | 62 +- init/fish.in | 2 + init/fish_complete.fish.in | 232 ----- init/fish_function.fish | 851 ------------------ init/functions/__fish_complete_directory.fish | 22 + .../functions/__fish_complete_subcommand.fish | 36 + init/functions/__fish_complete_suffix.fish | 26 + init/functions/__fish_contains_opt.fish | 53 ++ init/functions/__fish_gnu_complete.fish | 29 + init/functions/__fish_move_last.fish | 27 + init/functions/__fish_print_packages.fish | 55 ++ init/functions/dirh.fish | 26 + init/functions/help.fish | 94 ++ init/functions/ls.fish | 18 + init/functions/nextd.fish | 50 + init/functions/open.fish | 12 + init/functions/prevd.fish | 51 ++ init/functions/psub.fish | 54 ++ init/functions/trap.fish | 136 +++ init/functions/type.fish | 134 +++ init/functions/umask.fish | 206 +++++ init/functions/vared.fish | 47 + main.c | 2 + parse_util.c | 156 ++++ parse_util.h | 11 + parser.c | 2 +- 31 files changed, 1319 insertions(+), 1229 deletions(-) create mode 100644 init/functions/__fish_complete_directory.fish create mode 100644 init/functions/__fish_complete_subcommand.fish create mode 100644 init/functions/__fish_complete_suffix.fish create mode 100644 init/functions/__fish_contains_opt.fish create mode 100644 init/functions/__fish_gnu_complete.fish create mode 100644 init/functions/__fish_move_last.fish create mode 100644 init/functions/__fish_print_packages.fish create mode 100644 init/functions/dirh.fish create mode 100644 init/functions/help.fish create mode 100644 init/functions/ls.fish create mode 100644 init/functions/nextd.fish create mode 100644 init/functions/open.fish create mode 100644 init/functions/prevd.fish create mode 100644 init/functions/psub.fish create mode 100644 init/functions/trap.fish create mode 100644 init/functions/type.fish create mode 100644 init/functions/umask.fish create mode 100644 init/functions/vared.fish diff --git a/Makefile.in b/Makefile.in index 255f016e5..fd1f72f56 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/common.c b/common.c index 25f0b5443..103c5beac 100644 --- a/common.c +++ b/common.c @@ -287,6 +287,7 @@ wchar_t *str2wcs( const char *in ) { return out; } + default: { in_pos += res; diff --git a/complete.c b/complete.c index 4c2d0680c..00dc6dd66 100644 --- a/complete.c +++ b/complete.c @@ -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; iis_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,7 +119,8 @@ 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 ); for( i=0; icmd; @@ -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; diff --git a/init/fish.in b/init/fish.in index c67a4a5f8..344484c7c 100644 --- a/init/fish.in +++ b/init/fish.in @@ -87,6 +87,8 @@ if test 1 = "@HAVE_GETTEXT@" end end +set -g fish_function_path $PWD/fish.d/functions + # # Load additional initialization files # diff --git a/init/fish_complete.fish.in b/init/fish_complete.fish.in index ac8b40566..42619251f 100644 --- a/init/fish_complete.fish.in +++ b/init/fish_complete.fish.in @@ -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] diff --git a/init/fish_function.fish b/init/fish_function.fish index 47fa0e883..4ddadc35f 100644 --- a/init/fish_function.fish +++ b/init/fish_function.fish @@ -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 diff --git a/init/functions/__fish_complete_directory.fish b/init/functions/__fish_complete_directory.fish new file mode 100644 index 000000000..af3844d5a --- /dev/null +++ b/init/functions/__fish_complete_directory.fish @@ -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 + diff --git a/init/functions/__fish_complete_subcommand.fish b/init/functions/__fish_complete_subcommand.fish new file mode 100644 index 000000000..60ecc35a9 --- /dev/null +++ b/init/functions/__fish_complete_subcommand.fish @@ -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 + diff --git a/init/functions/__fish_complete_suffix.fish b/init/functions/__fish_complete_suffix.fish new file mode 100644 index 000000000..78c5d2e00 --- /dev/null +++ b/init/functions/__fish_complete_suffix.fish @@ -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 diff --git a/init/functions/__fish_contains_opt.fish b/init/functions/__fish_contains_opt.fish new file mode 100644 index 000000000..5b06007e6 --- /dev/null +++ b/init/functions/__fish_contains_opt.fish @@ -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 + diff --git a/init/functions/__fish_gnu_complete.fish b/init/functions/__fish_gnu_complete.fish new file mode 100644 index 000000000..9aeb0ba8b --- /dev/null +++ b/init/functions/__fish_gnu_complete.fish @@ -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 + diff --git a/init/functions/__fish_move_last.fish b/init/functions/__fish_move_last.fish new file mode 100644 index 000000000..965072cda --- /dev/null +++ b/init/functions/__fish_move_last.fish @@ -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 + diff --git a/init/functions/__fish_print_packages.fish b/init/functions/__fish_print_packages.fish new file mode 100644 index 000000000..03e523140 --- /dev/null +++ b/init/functions/__fish_print_packages.fish @@ -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 + diff --git a/init/functions/dirh.fish b/init/functions/dirh.fish new file mode 100644 index 000000000..82eb5a292 --- /dev/null +++ b/init/functions/dirh.fish @@ -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 + diff --git a/init/functions/help.fish b/init/functions/help.fish new file mode 100644 index 000000000..1dff5f916 --- /dev/null +++ b/init/functions/help.fish @@ -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 diff --git a/init/functions/ls.fish b/init/functions/ls.fish new file mode 100644 index 000000000..3f96812a3 --- /dev/null +++ b/init/functions/ls.fish @@ -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 + diff --git a/init/functions/nextd.fish b/init/functions/nextd.fish new file mode 100644 index 000000000..293e7fd95 --- /dev/null +++ b/init/functions/nextd.fish @@ -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 diff --git a/init/functions/open.fish b/init/functions/open.fish new file mode 100644 index 000000000..bfe0f99e1 --- /dev/null +++ b/init/functions/open.fish @@ -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 + diff --git a/init/functions/prevd.fish b/init/functions/prevd.fish new file mode 100644 index 000000000..e71fb2e04 --- /dev/null +++ b/init/functions/prevd.fish @@ -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 + diff --git a/init/functions/psub.fish b/init/functions/psub.fish new file mode 100644 index 000000000..974833f21 --- /dev/null +++ b/init/functions/psub.fish @@ -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 diff --git a/init/functions/trap.fish b/init/functions/trap.fish new file mode 100644 index 000000000..74940dbe3 --- /dev/null +++ b/init/functions/trap.fish @@ -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 diff --git a/init/functions/type.fish b/init/functions/type.fish new file mode 100644 index 000000000..af7e0faa2 --- /dev/null +++ b/init/functions/type.fish @@ -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 + diff --git a/init/functions/umask.fish b/init/functions/umask.fish new file mode 100644 index 000000000..5392a390c --- /dev/null +++ b/init/functions/umask.fish @@ -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 diff --git a/init/functions/vared.fish b/init/functions/vared.fish new file mode 100644 index 000000000..f6b442b5f --- /dev/null +++ b/init/functions/vared.fish @@ -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 + diff --git a/main.c b/main.c index b277ba0ac..1744451a3 100644 --- a/main.c +++ b/main.c @@ -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(); diff --git a/parse_util.c b/parse_util.c index b0c559cb5..620241899 100644 --- a/parse_util.c +++ b/parse_util.c @@ -13,6 +13,7 @@ #include +#include #include #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; iskip ) { int nxt_forbidden; wchar_t *forbid;