From cf8e746d0c04aec16df8e69d2987c785cb510d46 Mon Sep 17 00:00:00 2001 From: liljencrantz Date: Wed, 26 Sep 2007 02:14:47 +1000 Subject: First stab at dropping all support for readlines inputrc files and instead using an internal system for performing keybinding. darcs-hash:20070925161447-75c98-1feaef88a4b518badb7879f598f06ab650a8f93b.gz --- builtin.c | 254 +++- builtin_commandline.c | 2 +- doc_src/bind.txt | 48 +- etc/fish_inputrc | 28 - input.c | 1690 +++++------------------- input.h | 40 +- share/completions/bind.fish | 11 +- share/functions/__fish_bind_test1.fish | 27 + share/functions/__fish_bind_test2.fish | 20 + share/functions/__fish_config_interactive.fish | 29 +- share/functions/fish_default_key_bindings.fish | 91 ++ 11 files changed, 819 insertions(+), 1421 deletions(-) delete mode 100644 etc/fish_inputrc create mode 100644 share/functions/__fish_bind_test1.fish create mode 100644 share/functions/__fish_bind_test2.fish create mode 100644 share/functions/fish_default_key_bindings.fish diff --git a/builtin.c b/builtin.c index cd412bdb..6b0b9979 100644 --- a/builtin.c +++ b/builtin.c @@ -402,28 +402,183 @@ static void builtin_missing_argument( const wchar_t *cmd, const wchar_t *opt ) #include "builtin_ulimit.c" #include "builtin_jobs.c" +static void builtin_bind_list() +{ + array_list_t lst; + int i; + + + al_init( &lst ); + input_mapping_get_names( &lst ); + + for( i=0; ibind [OPTIONS] [BINDINGS...] +bind [OPTIONS] SEQUENCE COMMAND -The bind builtin causes fish to add the readline style bindings specified by BINDINGS to the list of key bindings, as if they appeared in your ~/.fish_inputrc file. +\subsection bind-description Description -For more information on the syntax keyboard bindings, use man -readline to access the readline documentation. The available commands -are listed in the Command Line Editor section -of the fish manual - but you may also use any fish command! To write such -commands, see the commandline builtin. It's good -practice to put the code into a function -b -and bind to the function name. +The bind builtin causes fish to add a key binding from the specified sequence. + +SEQUENCE is the character sequence to bind to. Usually, one would use +fish escape sequences to express them. For example, Alt-w can be +written as \\ew, and Control-x can be written as +\\cx. + +If the -k switch is used, the name of the key (such as down, up or +backspace) is used instead of a sequence. The names used are the same +as the corresponding curses variables, but without the 'key_' +prefix. (See man 5 terminfo for more information, or use bind +--names for a list of all available named keys) + +COMMAND can be any fish command, but it can also be one of a set of +special input functions. These include functions for moving the +cursor, operating on the kill-ring, performing tab completion, +etc. Use 'bind -N' for a complete list of these input functions. + +When COMMAND is a shellscript command, it is a good practice to put +the actual code into a function and simply +bind to the function name. + +- -a or --all If --print-key-names is specified, show all key names, not only the ones that actually are defined for the current terminal. If erase mode is specified, this switch will cause all current bindings to be erased. +- -e or --erase Erase mode. All non-switch arguments are interpreted as character sequences and any commands associated with those sequences are erased. +- -h or --help Display help and exit +- -k or --key Specify a key name, such as 'left' or 'backspace' instead of a character sequence +- -K or --key-names Display a list of available key names +- -f or --function-names Display a list of available input functions -\subsection bind-description Description -- -M MODE or --set-mode=MODE sets the current input mode to MODE. \subsection bind-example Example -bind -M vi changes to the vi input mode +bind \cd 'exit' causes fish to exit on Control-d + +bind -k ppage history-search-backward Causes fish to perform a history search when the page up key is pressed -bind '"\\M-j": jobs' Binds the jobs command to the Alt-j keyboard shortcut diff --git a/etc/fish_inputrc b/etc/fish_inputrc deleted file mode 100644 index 981b0abe..00000000 --- a/etc/fish_inputrc +++ /dev/null @@ -1,28 +0,0 @@ -# -# This file contains key bindings for fish -# - -# Include system-wide inputrc file before including fish-specific key -# bindings if it exists - -$include /etc/inputrc - -$if fish - "\M-l": __fish_list_current_token - "\M-w": set tok (commandline -pt); if test $tok[1]; whatis $tok[1]; commandline -f repaint; end - "\C-l": clear; commandline -f repaint - "\C-c": delete-line - "\C-u": backward-kill-line - "\M-d": kill-word - "\C-w": backward-kill-word - "\M-k": dump-functions - "\M-d": if test -z (commandline); dirh; commandline -f repaint; else; commandline -f kill-word; end - "\C-d": delete-or-exit -# This will make sure the output of the current command is paged using the less pager when you press Meta-p - "\M-p": if commandline -j|grep -v 'less *$' >/dev/null; commandline -aj "|less;"; end -$endif - -# Include user-specific inputrc file after including fish-specific -# bindings so that they will override fish defaults - -$include ~/.inputrc diff --git a/input.c b/input.c index 8b913e01..d0b89840 100644 --- a/input.c +++ b/input.c @@ -70,31 +70,43 @@ implementation in fish is as of yet incomplete. #include "output.h" #include "intern.h" - -static void input_read_inputrc( wchar_t *fn ); +#include "halloc.h" +#include "halloc_util.h" /** - Array containing characters which have been peeked by the escape - sequence matching functions and returned + Add a new terminfo mapping */ +#define TERMINFO_ADD(key) \ + { \ + terminfo_mapping_t *m = halloc( terminfo_mappings, sizeof( terminfo_mapping_t ) ); \ + m->name = halloc_wcsdup( terminfo_mappings, (L ## #key)+4 ); \ + m->seq = key; \ + al_push( terminfo_mappings, m ); \ + } + +/** + Struct representing a keybinding. Returned by input_get_mappings. + */ typedef struct { const wchar_t *seq; /**< Character sequence which generates this event */ - const wchar_t *seq_desc; /**< Description of the character sequence suitable for printing on-screen */ const wchar_t *command; /**< command that should be evaluated by this mapping */ } - mapping; + input_mapping_t; /** - Symbolic names for some acces-modifiers used when parsing symbolic sequences -*/ -#define CTRL_SYMBOL L"Control-" -/** - Symbolic names for some acces-modifiers used when parsing symbolic sequences -*/ -#define META_SYMBOL L"Meta-" + A struct representing the mapping from a terminfo key name to a terminfo character sequence + */ +typedef struct +{ + const wchar_t *name; /**< Name of key */ + const char *seq; /**< Character sequence generated on keypress */ + +} + terminfo_mapping_t; + /** Names of all the readline functions supported @@ -179,6 +191,7 @@ static const wchar_t *desc_arr[] = } ; */ + /** Internal code for each supported readline function */ @@ -224,68 +237,24 @@ static const wchar_t code_arr[] = ; -/** - List of all key bindings, as mappings from one sequence to either a character or a command -*/ -static hash_table_t all_mappings; - /** Mappings for the current input mode */ -static array_list_t *current_mode_mappings; -/** - Mappings for the current application -*/ -static array_list_t *current_application_mappings; -/** - Global mappings -*/ -static array_list_t *global_mappings; +static array_list_t mappings = {0,0,0}; -/** - Number of nested conditional statement levels that are not evaluated -*/ -static int inputrc_skip_block_count=0; -/** - Number of nested conditional statements that have evaluated to true -*/ -static int inputrc_block_count=0; +static array_list_t *terminfo_mappings = 0; -/** - True if syntax errors were found in the inputrc file -*/ -static int inputrc_error = 0; /** Set to one when the input subsytem has been initialized. */ static int is_init = 0; -/** - This is the variable telling us how many timew the next command - should bne repeated. Only actually used in vi-mode. -*/ -static int repeat_count = 1; +static void input_terminfo_init(); +static void input_terminfo_destroy(); -/** - This is the type of the first command in a vi-mode two-part combo - like 'dw' or '3d3l'. -*/ -static wint_t first_command = 0; -wchar_t input_get_code( const wchar_t *name ) -{ - int i; - for( i = 0; i<(sizeof( code_arr )/sizeof(wchar_t)) ; i++ ) - { - if( wcscmp( name, name_arr[i] ) == 0 ) - { - return code_arr[i]; - } - } - return -1; -} /** Returns the function name for the given function code. @@ -323,1430 +292,487 @@ static const wchar_t *input_get_desc( wchar_t c ) return 0; } */ -void input_set_mode( wchar_t *name ) -{ - current_mode_mappings = (array_list_t *)hash_get( &all_mappings, name ); -} - -void input_set_application( wchar_t *name ) -{ - current_application_mappings = (array_list_t *)hash_get( &all_mappings, name ); -} - -/** - Get the mapping with the specified name -*/ -static array_list_t *get_mapping( const wchar_t *mode ) -{ - - array_list_t * mappings = (array_list_t *)hash_get( &all_mappings, mode ); - - if( !mappings ) - { - mappings = malloc( sizeof( array_list_t )); - al_init( mappings ); - - hash_put( &all_mappings, wcsdup(mode), mappings ); - - } - return mappings; - -} -void add_mapping( const wchar_t *mode, - const wchar_t *s, - const wchar_t *d, - const wchar_t *c ) +void input_mapping_add( const wchar_t *sequence, + const wchar_t *command ) { int i; - array_list_t *mappings; - - if( s == 0 ) - return; + CHECK( sequence, ); + CHECK( command, ); - if( mode == 0 ) - return; + // debug( 0, L"Add mapping from %ls to %ls", escape(sequence, 1), escape(command, 1 ) ); - mappings = get_mapping( mode ); - - for( i=0; iseq, s ) == 0 ) + input_mapping_t *m = (input_mapping_t *)al_get( &mappings, i ); + if( wcscmp( m->seq, sequence ) == 0 ) { - m->seq_desc = intern(d); - m->command = intern(c); + m->command = intern(command); return; } } - mapping *m = malloc( sizeof( mapping ) ); - m->seq = intern( s ); - m->seq_desc = intern(d ); - m->command = intern(c); - al_push( mappings, m ); + input_mapping_t *m = malloc( sizeof( input_mapping_t ) ); + m->seq = intern( sequence ); + m->command = intern(command); + al_push( &mappings, m ); + } /** - Compare sort order for two keyboard mappings. This function is made - to be suitable for use with the qsort method. + Handle interruptions to key reading by reaping finshed jobs and + propagating the interrupt to the reader. */ -/* -static int mapping_compare( const void *a, const void *b ) +static int interrupt_handler() { - mapping *c = *(mapping **)a; - mapping *d = *(mapping **)b; - -// fwprintf( stderr, L"%ls %ls\n", c->seq_desc, d->seq_desc ); - - return wcscmp( c->seq_desc, d->seq_desc ); + /* + Fire any pending events + */ + event_fire( 0 ); -} -*/ + /* + Reap stray processes, including printing exit status messages + */ + if( job_reap( 1 ) ) + repaint(); + + /* + Check if we should exit + */ + if( exit_status() ) + { + return R_EXIT; + } + + /* + Tell the reader an event occured + */ + if( reader_interrupted() ) + { + /* + Return 3, i.e. the character read by a Control-C. + */ + return 3; + } + return R_WINCH; +} -/** - Print a listing of all keybindings and a description of each - function. This is used by the dump-functions readline function. -*/ -static void dump_functions() +int input_init() { -/* int i; - fwprintf( stdout, L"\n" ); - - qsort(current_mappings.arr, - al_get_count( &mappings), - sizeof( void*), - &mapping_compare ); + if( is_init ) + return 1; - for( i=0; iseq ); -fwprintf( stdout, -L"%ls: %ls\n", -m->seq_desc, -m->command ); -} -repaint();*/ -} + is_init = 1; + input_common_init( &interrupt_handler ); -/** - Parse special character from the specified inputrc-style key binding. + if( setupterm( 0, STDOUT_FILENO, 0) == ERR ) + { + debug( 0, _( L"Could not set up terminal" ) ); + exit(1); + } + output_set_term( env_get( L"TERM" ) ); + + input_terminfo_init(); + - Control-a is expanded to 1, etc. -*/ + return 1; +} -static wchar_t *input_symbolic_sequence( const wchar_t *in ) +void input_destroy() { - wchar_t *res=0; - - if( !*in || *in == L'\n' ) - return 0; + if( !is_init ) + return; - debug( 4, L"Try to parse symbolic sequence %ls", in ); - - if( wcsncmp( in, CTRL_SYMBOL, wcslen(CTRL_SYMBOL) ) == 0 ) - { - int has_meta=0; - - in += wcslen(CTRL_SYMBOL); - - /* - Control-Meta- Should be rearranged to Meta-Control, this - special-case must be handled manually. - */ - if( wcsncmp( in, META_SYMBOL, wcslen(META_SYMBOL) ) == 0 ) - { - in += wcslen(META_SYMBOL); - has_meta=1; - } - - wchar_t c = towlower( *in ); - in++; - if( c < L'a' || c > L'z' ) - { - debug( 1, _( L"Invalid Control sequence" ) ); - return 0; - } - if( has_meta ) - { - res = wcsdup( L"\x1ba" ); - res[1]=1+c-L'a'; - } - else - { - res = wcsdup( L"a" ); - res[0]=1+c-L'a'; - } - debug( 4, L"Got control sequence %d", res[0] ); - } - else if( wcsncmp( in, META_SYMBOL, wcslen(META_SYMBOL) ) == 0 ) - { - in += wcslen(META_SYMBOL); - res = wcsdup( L"\x1b" ); - debug( 4, L"Got meta" ); - } - else - { - int i; - struct - { - wchar_t *in; - char *out; - } - map[]= - { - { - L"rubout", - key_backspace - } - , - { - L"del", - key_dc - } - , - { - L"esc", - "\x1b" - } - , - { - L"lfd", - "\r" - } - , - { - L"newline", - "\n" - } - , - { - L"ret", - "\n" - } - , - { - L"return", - "\n" - } - , - { - L"spc", - " " - } - , - { - L"space", - " " - } - , - { - L"tab", - "\t" - } - , - { - 0, - 0 - } - } - ; - - for( i=0; map[i].in; i++ ) - { - if( wcsncasecmp( in, map[i].in, wcslen(map[i].in) )==0 ) - { - in+= wcslen( map[i].in ); - res = str2wcs( map[i].out ); - - break; - } - } + is_init=0; + + al_foreach( &mappings, &free ); + al_destroy( &mappings ); - if( !res ) - { - if( iswalnum( *in ) || iswpunct( *in ) ) - { - res = wcsdup( L"a" ); - *res = *in++; - debug( 4, L"Got character %lc", *res ); - } - } - } - if( !res ) - { - debug( 1, _( L"Could not parse sequence '%ls'" ), in ); - return 0; - } - if( !*in || *in == L'\n') - { - debug( 4, L"Finished parsing sequence" ); - return res; - } + input_common_destroy(); - wchar_t *res2 = input_symbolic_sequence( in ); - if( !res2 ) + if( del_curterm( cur_term ) == ERR ) { - free( res ); - return 0; + debug( 0, _(L"Error while closing terminfo") ); } - wchar_t *res3 = wcsdupcat( res, res2 ); - free( res); - free(res2); + + input_terminfo_destroy(); - return res3; } /** - Unescape special character from the specified inputrc-style key sequence. - - \\C-a is expanded to 1, etc. + Perform the action of the specified binding */ -static wchar_t *input_expand_sequence( const wchar_t *in ) +static wint_t input_exec_binding( input_mapping_t *m, const wchar_t *seq ) { - const wchar_t *in_orig=in; - wchar_t *res = malloc( sizeof( wchar_t)*(4*wcslen(in)+1)); - wchar_t *out=res; - int error = 0; - - while( *in && !error) - { - switch( *in ) + wchar_t code = input_function_get_code( m->command ); + if( code != -1 ) + { + switch( code ) { - case L'\\': - { - in++; - switch( *in ) - { - case L'\0': - error = 1; - break; - - case L'e': - *(out++)=L'\x1b'; - break; - - case L'\\': - case L'\"': - case L'\'': - *(out++)=*in; - break; - - case L'b': - *(out++)=L'\b'; - break; - - case L'd': - { - wchar_t *str = str2wcs( key_dc ); - wchar_t *p=str; - if( p ) - { - while( *p ) - { - *(out++)=*(p++); - } - free( str ); - } - break; - } - - case L'f': - *(out++)=L'\f'; - break; - - case L'n': - *(out++)=L'\n'; - break; - - case L'r': - *(out++)=L'\r'; - break; - - case L't': - *(out++)=L'\t'; - break; - - case L'v': - *(out++)=L'\v'; - break; - - /* - Parse numeric backslash escape - */ - case L'u': - case L'U': - case L'x': - case L'o': - { - int i; - wchar_t res=0; - int chars=2; - int base=16; - - switch( *in++ ) - { - case L'u': - base=16; - chars=4; - break; - - case L'U': - base=16; - chars=8; - break; - - case L'x': - base=16; - chars=2; - break; - - case L'o': - base=8; - chars=3; - break; - - } - - for( i=0; i= L'a') && - (*in < L'a'+32) ) - { - if( has_escape ) - *(out++)=L'\x1b'; - *(out++)=*in-L'a'+1; - break; - } - - if( (*in >= L'A') && - (*in < L'A'+32) ) - { - if( has_escape ) - *(out++)=L'\x1b'; - *(out++)=*in-L'A'+1; - break; - } - debug( 1, _( L"Invalid sequence - Control-nothing?\n" ) ); - error = 1; - - break; - } - - /* - Parse meta sequence - */ - case L'M': - { - in++; - if( *in != L'-' ) - { - error=1; - debug( 1, _( L"Invalid sequence - no dash after meta\n" ) ); - break; - } - if( !*(in+1) ) - { - debug( 1, _( L"Invalid sequence - Meta-nothing?" ) ); - error=1; - break; - } - *(out++)=L'\x1b'; - - break; - } - - default: - { - *(out++)=*in; - break; - } - - } - - break; + case R_SELF_INSERT: + { + return seq[0]; } + default: { - *(out++)=*in; - break; + return code; } + } - in++; - } - - - - if( error ) - { - free( res); - res=0; } else { -// fwprintf( stderr, L"%ls translated ok\n", in_orig ); - *out = L'\0'; - } - - if( !error ) - { - if( wcslen( res ) == 0 ) - { - debug( 1, _( L"Invalid sequence - '%ls' expanded to zero characters" ), in_orig ); - error =1; - res = 0; - } - } + + /* + This key sequence is bound to a command, which + is sent to the parser for evaluation. + */ + + eval( m->command, 0, TOP ); + + /* + We still need to return something to the caller, R_NULL + tells the reader that no key press needs to be handled, + and no repaint is needed. + + Bindings that produce output should emit a R_REPAINT + function by calling 'commandline -f repaint' to tell + fish that a repaint is in order. + */ + + return R_NULL; - return res; + } } -void input_parse_inputrc_line( wchar_t *cmd ) -{ - wchar_t *p=cmd; - - /* Make all whitespace into space characters */ - while( *p ) - { - if( *p == L'\t' || *p == L'\r' ) - *p=L' '; - p++; - } - /* Remove spaces at beginning/end */ - while( *cmd == L' ' ) - cmd++; - - p = cmd + wcslen(cmd)-1; - while( (p >= cmd) && (*p == L' ') ) +/** + Try reading the specified function mapping +*/ +static wint_t input_try_mapping( input_mapping_t *m) +{ + int j, k; + wint_t c=0; + + /* + Check if the actual function code of this mapping is on the stack + */ + c = input_common_readch( 0 ); + if( c == input_function_get_code( m->command ) ) { - *p=L'\0'; - p--; + return input_exec_binding( m, m->seq ); } - - /* Skip comments */ - if( *cmd == L'#' ) - return; - - /* Skip empty lines */ - if( *cmd == L'\0' ) - return; + input_unreadch( c ); - if( wcscmp( L"$endif", cmd) == 0 ) + if( m->seq != 0 ) { - if( inputrc_skip_block_count ) + + for( j=0; m->seq[j] != L'\0' && + m->seq[j] == (c=input_common_readch( j>0 )); j++ ) + ; + + if( m->seq[j] == L'\0' ) { - inputrc_skip_block_count--; -/* - if( !inputrc_skip_block_count ) - fwprintf( stderr, L"Stop skipping\n" ); - else - fwprintf( stderr, L"Decrease skipping\n" ); -*/ + return input_exec_binding( m, m->seq ); } else { - if( inputrc_block_count ) - { - inputrc_block_count--; -// fwprintf( stderr, L"End of active block\n" ); - } - else - { - inputrc_error = 1; - debug( 1, - _( L"Mismatched $endif in inputrc file" ) ); - } - } - return; - } - - if( wcscmp( L"$else", cmd) == 0 ) - { - if( inputrc_skip_block_count ) - { - if( inputrc_skip_block_count == 1 ) + /* + Return the read characters + */ + input_unreadch(c); + for( k=j-1; k>=0; k-- ) { - inputrc_skip_block_count--; - inputrc_block_count++; + input_unreadch( m->seq[k] ); } - - } - else - { - inputrc_skip_block_count++; - inputrc_block_count--; } - - return; } - - if( inputrc_skip_block_count ) - { - if( wcsncmp( L"$if ", cmd, wcslen( L"$if " )) == 0 ) - inputrc_skip_block_count++; -// fwprintf( stderr, L"Skip %ls\n", cmd ); + return 0; - return; - } - - if( *cmd == L'\"' ) - { +} - wchar_t *key; - wchar_t *val; - wchar_t *sequence; - wchar_t prev=0; - +void input_unreadch( wint_t ch ) +{ + input_common_unreadch( ch ); +} - cmd++; - key=cmd; - - for( prev=0; ;prev=*cmd,cmd++ ) - { - if( !*cmd ) - { - debug( 1, - _( L"Mismatched quote" ) ); - inputrc_error = 1; - return; - } - - if(( *cmd == L'\"' ) && prev != L'\\' ) - break; - - } - *cmd=0; - cmd++; - if( *cmd != L':' ) - { - debug( 1, - _( L"Expected a \':\'" ) ); - inputrc_error = 1; - return; - } - cmd++; - while( *cmd == L' ' ) - cmd++; - - val = cmd; - - sequence = input_expand_sequence( key ); - if( sequence ) - { - add_mapping( L"global", sequence, key, val ); - free( sequence ); - } - - return; - } - else if( wcsncmp( L"$include ", cmd, wcslen(L"$include ") ) == 0 ) - { - wchar_t *tmp; - - cmd += wcslen( L"$include "); - while( *cmd == L' ' ) - cmd++; - tmp=wcsdup(cmd); - tmp = expand_tilde(tmp); - if( tmp ) - input_read_inputrc( tmp ); - free(tmp); - return; - } - else if( wcsncmp( L"set", cmd, wcslen( L"set" ) ) == 0 ) - { - wchar_t *set, *key, *value, *end; - wchar_t *state; - - set = wcstok( cmd, L" \t", &state ); - key = wcstok( 0, L" \t", &state ); - value = wcstok( 0, L" \t", &state ); - end = wcstok( 0, L" \t", &state ); +wint_t input_readch() +{ + + int i; - if( wcscmp( set, L"set" ) != 0 ) - { - debug( 1, _( L"I don\'t know what '%ls' means" ), set ); - } - else if( end ) - { - debug( 1, _( L"Expected end of line, got '%ls'" ), end ); - - } - else if( (!key) || (!value) ) - { - debug( 1, _( L"Syntax: set KEY VALUE" ) ); - } - else - { - if( wcscmp( key, L"editing-mode" ) == 0 ) - { - current_mode_mappings = get_mapping( value ); - } - } - - return; - } - else if( wcsncmp( L"$if ", cmd, wcslen( L"$if " )) == 0 ) + CHECK_BLOCK( R_NULL ); + + /* + Clear the interrupted flag + */ + reader_interrupted(); + + /* + Search for sequence in various mapping tables + */ + + while( 1 ) { - wchar_t *term_line = wcsdupcat( L"term=", env_get( L"TERM" ) ); - wchar_t *term_line2 = wcsdup( term_line ); - wchar_t *mode_line = L"mode=emacs"; - wchar_t *app_line = L"fish"; - - wchar_t *term_line2_end = wcschr( term_line2, L'-' ); - if( term_line2_end ) - *term_line2_end=0; - - - cmd += wcslen( L"$if "); - while( *cmd == L' ' ) - cmd++; - - if( (wcscmp( cmd, app_line )==0) || - (wcscmp( cmd, term_line )==0) || - (wcscmp( cmd, mode_line )==0) ) - { -// fwprintf( stderr, L"Conditional %ls is true\n", cmd ); - inputrc_block_count++; - } - else + for( i=0; iseq) == 0 ) + { + wchar_t arr[2]= + { + 0, + 0 + } + ; + arr[0] = input_common_readch(0); + + return input_exec_binding( m, arr ); + } } - *cmd = 0; - - cmd++; - - while( *cmd == L' ' ) - cmd++; - - val = cmd; - debug( 3, L"Map %ls to %ls\n", key, val ); + /* + No action to take on specified character, ignoer it + and move to next one. + */ + input_common_readch( 0 ); - sequence = input_symbolic_sequence( key ); - if( sequence ) - { - add_mapping( L"global", sequence, key, val ); - free( sequence ); - } - - return; - + } +} + +void input_mapping_get_names( array_list_t *list ) +{ + int i; + + for( i=0; iseq ); } - debug( 1, _( L"I don\'t know what %ls means" ), cmd ); } -/** - Read the specified inputrc file -*/ -static void input_read_inputrc( wchar_t *fn ) + +int input_mapping_erase( const wchar_t *sequence ) { - FILE *rc; - wchar_t *buff=0; - int buff_len=0; - int error=0; -// fwprintf( stderr, L"read %ls\n", fn ); - - signal_block(); - rc = wfopen( fn, "r" ); + int ok = 0; + int i; + size_t sz = al_get_count( &mappings ); - if( rc ) - { - while( !feof( rc ) && (!error)) + for( i=0; iseq ) ) { - switch( fgetws2( &buff, &buff_len, rc ) ) + if( i != (sz-1 ) ) { - case -1: - { - debug( 1, - _( L"Error while reading input information from file '%ls'" ), - fn ); - - wperror( L"fgetws2 (read_ni)" ); - error=1; - break; - } - - default: - { - input_parse_inputrc_line( buff ); - - if( inputrc_error ) - { - fwprintf( stderr, L"%ls\n", buff ); - error=1; - } - } + al_set( &mappings, i, al_get( &mappings, sz -1 ) ); } + al_truncate( &mappings, sz-1 ); + ok = 1; + + free( m ); + + break; + } - free( buff ); - /* - Don't need to check exit status of fclose on read-only stream - */ - fclose( rc ); + } - signal_unblock(); + + return ok; - inputrc_skip_block_count=0; - inputrc_block_count=0; } -/** - Add a char * based character string mapping. -*/ -static void add_terminfo_mapping( const wchar_t *mode, - const char *seq, - const wchar_t *desc, - const wchar_t *func ) +const wchar_t *input_mapping_get( const wchar_t *sequence ) { - if( seq ) + int i; + size_t sz = al_get_count( &mappings ); + + for( i=0; iseq ) ) { - add_mapping( mode, tmp, desc, func ); - free(tmp); + return m->command; } } - + return 0; } - /** - Call input_expand_sequence on seq, and add the result as a mapping -*/ -static void add_escaped_mapping( const wchar_t *mode, - const wchar_t *seq, - const wchar_t *desc, - const wchar_t *func ) + Add all terminfo mappings + */ +static void input_terminfo_init() { - wchar_t *esc = input_expand_sequence( seq ); - if( esc ) - { - add_mapping( mode, esc, desc, func ); - free(esc); - } + terminfo_mappings = al_halloc( 0 ); + + TERMINFO_ADD( key_down ); + TERMINFO_ADD( key_up ); + TERMINFO_ADD( key_left ); + TERMINFO_ADD( key_right ); + TERMINFO_ADD( key_dc ); + TERMINFO_ADD( key_backspace ); + TERMINFO_ADD( key_home ); + TERMINFO_ADD( key_end ); + TERMINFO_ADD( key_ppage ); + TERMINFO_ADD( key_npage ); + TERMINFO_ADD( key_clear ); + TERMINFO_ADD( key_close ); + TERMINFO_ADD( key_command ); + TERMINFO_ADD( key_copy ); + TERMINFO_ADD( key_create ); + TERMINFO_ADD( key_dl ); + TERMINFO_ADD( key_enter ); + TERMINFO_ADD( key_undo ); + TERMINFO_ADD( key_suspend ); + TERMINFO_ADD( key_cancel ); } -/** - Add bindings common to emacs and vi -*/ -static void add_common_bindings() +static void input_terminfo_destroy() { - static const wchar_t *name[] = - { - L"emacs", - L"vi", - L"vi-command" - } - ; - int i; - /* - Universal bindings - */ - for( i=0; i<3; i++ ) + if( terminfo_mappings ) { - add_mapping( name[i], L"\n", L"Execute contents of commandline", L"execute" ); - - /* - This will make Meta-newline insert a newline, since - self-insert ignored the escape character unless it is the - only character of the sequence. - */ - add_mapping( name[i], L"\x1b\n", L"Meta-newline", L"self-insert" ); - /* - We need alternative keybidnings for arrowkeys, since - terminfo sometimes specifies a different sequence than what - keypresses actually generate - */ - add_mapping( name[i], L"\x1b[A", L"Up", L"up-or-search" ); - add_mapping( name[i], L"\x1b[B", L"Down", L"down-or-search" ); - add_terminfo_mapping( name[i], (key_up), L"Up", L"up-or-search" ); - add_terminfo_mapping( name[i], (key_down), L"Down", L"down-or-search" ); - - add_mapping( name[i], L"\x1b[C", L"Right", L"forward-char" ); - add_mapping( name[i], L"\x1b[D", L"Left", L"backward-char" ); - add_terminfo_mapping( name[i], (key_right), L"Right", L"forward-char" ); - add_terminfo_mapping( name[i], (key_left), L"Left", L"backward-char" ); - - add_terminfo_mapping( name[i], (key_dc), L"Delete", L"delete-char" ); - - add_terminfo_mapping( name[i], (key_backspace), L"Backspace", L"backward-delete-char" ); - add_mapping( name[i], L"\x7f", L"Backspace", L"backward-delete-char" ); - - add_mapping( name[i], L"\x1b[H", L"Home", L"beginning-of-line" ); - add_mapping( name[i], L"\x1b[F", L"End", L"end-of-line" ); - add_terminfo_mapping( name[i], (key_home), L"Home", L"beginning-of-line" ); - add_terminfo_mapping( name[i], (key_end), L"End", L"end-of-line" ); - - /* - We need lots of alternative keybidnings, since terminal - emulators can't seem to agree on what sequence to generate, - and terminfo doesn't specify what sequence should be - generated - */ - - add_mapping( name[i], L"\x1b\x1bOC", L"Alt-Right", L"nextd-or-forward-word" ); - add_mapping( name[i], L"\x1b\x1bOD", L"Alt-Left", L"prevd-or-backward-word" ); - add_mapping( name[i], L"\x1b\x1b[C", L"Alt-Right", L"nextd-or-forward-word" ); - add_mapping( name[i], L"\x1b\x1b[D", L"Alt-Left", L"prevd-or-backward-word" ); - add_mapping( name[i], L"\x1bO3C", L"Alt-Right", L"nextd-or-forward-word" ); - add_mapping( name[i], L"\x1bO3D", L"Alt-Left", L"prevd-or-backward-word" ); - add_mapping( name[i], L"\x1b[3C", L"Alt-Right", L"nextd-or-forward-word" ); - add_mapping( name[i], L"\x1b[3D", L"Alt-Left", L"prevd-or-backward-word" ); - add_mapping( name[i], L"\x1b[1;3C", L"Alt-Right", L"nextd-or-forward-word" ); - add_mapping( name[i], L"\x1b[1;3D", L"Alt-Left", L"prevd-or-backward-word" ); - - add_mapping( name[i], L"\x1b\x1bOA", L"Alt-Up", L"history-token-search-backward" ); - add_mapping( name[i], L"\x1b\x1bOB", L"Alt-Down", L"history-token-search-forward" ); - add_mapping( name[i], L"\x1b\x1b[A", L"Alt-Up", L"history-token-search-backward" ); - add_mapping( name[i], L"\x1b\x1b[B", L"Alt-Down", L"history-token-search-forward" ); - add_mapping( name[i], L"\x1bO3A", L"Alt-Up", L"history-token-search-backward" ); - add_mapping( name[i], L"\x1bO3B", L"Alt-Down", L"history-token-search-forward" ); - add_mapping( name[i], L"\x1b[3A", L"Alt-Up", L"history-token-search-backward" ); - add_mapping( name[i], L"\x1b[3B", L"Alt-Down", L"history-token-search-forward" ); - add_mapping( name[i], L"\x1b[1;3A", L"Alt-Up", L"history-token-search-backward" ); - add_mapping( name[i], L"\x1b[1;3B", L"Alt-Down", L"history-token-search-forward" ); + halloc_free( terminfo_mappings ); } - - /* - Bindings used in emacs and vi mode, but not in vi-command mode - */ - for( i=0; i<2; i++ ) - { - add_mapping( name[i], L"\t", L"Tab", L"complete" ); - add_escaped_mapping( name[i], (L"\\C-k"), L"Control-k", L"kill-line" ); - add_escaped_mapping( name[i], (L"\\C-y"), L"Control-y", L"yank" ); - add_mapping( name[i], L"", L"Any key", L"self-insert" ); - } - } -/** - Add emacs-specific bindings -*/ -static void add_emacs_bindings() -{ - add_escaped_mapping( L"emacs", (L"\\C-a"), L"Control-a", L"beginning-of-line" ); - add_escaped_mapping( L"emacs", (L"\\C-e"), L"Control-e", L"end-of-line" ); - add_escaped_mapping( L"emacs", (L"\\M-y"), L"Alt-y", L"yank-pop" ); - add_escaped_mapping( L"emacs", (L"\\C-h"), L"Control-h", L"backward-delete-char" ); - add_escaped_mapping( L"emacs", (L"\\C-e"), L"Control-e", L"end-of-line" ); - add_escaped_mapping( L"emacs", (L"\\C-w"), L"Control-w", L"backward-kill-word" ); - add_escaped_mapping( L"emacs", (L"\\C-p"), L"Control-p", L"history-search-backward" ); - add_escaped_mapping( L"emacs", (L"\\C-n"), L"Control-n", L"history-search-forward" ); - add_escaped_mapping( L"emacs", (L"\\C-f"), L"Control-f", L"forward-char" ); - add_escaped_mapping( L"emacs", (L"\\C-b"), L"Control-b", L"backward-char" ); - add_escaped_mapping( L"emacs", (L"\x1b\x7f"), L"Alt-backspace", L"backward-kill-word" ); - add_escaped_mapping( L"emacs", (L"\x1bb"), L"Alt-b", L"backward-word" ); - add_escaped_mapping( L"emacs", (L"\x1bf"), L"Alt-f", L"forward-word" ); - add_escaped_mapping( L"emacs", (L"\x1bd"), L"Alt-d", L"forward-kill-word" ); - add_terminfo_mapping( L"emacs", (key_ppage), L"Page Up", L"beginning-of-history" ); - add_terminfo_mapping( L"emacs", (key_npage), L"Page Down", L"end-of-history" ); - add_escaped_mapping( L"emacs", (L"\x1b<"), L"Alt-<", L"beginning-of-buffer" ); - add_escaped_mapping( L"emacs", (L"\x1b>"), L"Alt->", L"end-of-buffer" ); -} - -/** - Add vi-specific bindings -*/ -static void add_vi_bindings() -{ - add_mapping( L"vi", L"\x1b", L"Escape", L"bind -M vi-command" ); - - add_mapping( L"vi-command", L"i", L"i", L"bind -M vi" ); - add_mapping( L"vi-command", L"I", L"I", L"bind -M vi" ); - add_mapping( L"vi-command", L"k", L"k", L"history-search-backward" ); - add_mapping( L"vi-command", L"j", L"j", L"history-search-forward" ); - add_mapping( L"vi-command", L" ", L"Space", L"forward-char" ); - add_mapping( L"vi-command", L"l", L"l", L"forward-char" ); - add_mapping( L"vi-command", L"h", L"h", L"backward-char" ); - add_mapping( L"vi-command", L"$", L"$", L"end-of-line" ); - add_mapping( L"vi-command", L"^", L"^", L"beginning-of-line" ); - add_mapping( L"vi-command", L"0", L"0", L"beginning-of-line" ); - - add_mapping( L"vi-command", L"b", L"b", L"backward-word" ); - add_mapping( L"vi-command", L"B", L"B", L"backward-word" ); - add_mapping( L"vi-command", L"w", L"w", L"forward-word" ); - add_mapping( L"vi-command", L"W", L"W", L"forward-word" ); - - add_mapping( L"vi-command", L"x", L"x", L"delete-char" ); - - add_mapping( L"vi-command", L"1", L"1", L"vi-arg-digit" ); - add_mapping( L"vi-command", L"2", L"2", L"vi-arg-digit" ); - add_mapping( L"vi-command", L"3", L"3", L"vi-arg-digit" ); - add_mapping( L"vi-command", L"4", L"4", L"vi-arg-digit" ); - add_mapping( L"vi-command", L"5", L"5", L"vi-arg-digit" ); - add_mapping( L"vi-command", L"6", L"6", L"vi-arg-digit" ); - add_mapping( L"vi-command", L"7", L"7", L"vi-arg-digit" ); - add_mapping( L"vi-command", L"8", L"8", L"vi-arg-digit" ); - add_mapping( L"vi-command", L"9", L"9", L"vi-arg-digit" ); - - - add_mapping( L"vi-command", L"d", L"d", L"vi-delete-to" ); - add_mapping( L"vi-command", L"D", L"D", L"vi-delete-to" ); - - -/* - movement ("h", "l"), word movement - ("b", "B", "w", "W", "e", "E"), moving to beginning and end of line - ("0", "^", "$"), and inserting and appending ("i", "I", "a", "A"), - changing and deleting ("c", "C", "d", "D"), character replacement and - deletion ("r", "x"), and finally yanking and pasting ("y", "p") -*/ - -} - -/** - Handle interruptions to key reading by reaping finshed jobs and - propagating the interrupt to the reader. -*/ -static int interrupt_handler() +const wchar_t *input_terminfo_get_sequence( const wchar_t *name ) { - /* - Fire any pending events - */ - event_fire( 0 ); + const char *res = 0; + int i; + static string_buffer_t *buff = 0; + int err = ENOENT; - /* - Reap stray processes, including printing exit status messages - */ - if( job_reap( 1 ) ) - repaint(); + CHECK( name, 0 ); + input_init(); - /* - Check if we should exit - */ - if( exit_status() ) + for( i=0; iname ) ) + { + res = m->seq; + err = EILSEQ; + break; + } } - /* - Tell the reader an event occured - */ - if( reader_interrupted() ) + if( !res ) { - /* - Return 3, i.e. the character read by a Control-C. - */ - return 3; + errno = err; + return 0; } - - return R_WINCH; -} - -int input_init() -{ - wchar_t *fn; - - if( is_init ) - return 1; - is_init = 1; - - input_common_init( &interrupt_handler ); - - if( setupterm( 0, STDOUT_FILENO, 0) == ERR ) + if( !buff ) { - debug( 0, _( L"Could not set up terminal" ) ); - exit(1); + buff = sb_halloc( global_context ); } - output_set_term( env_get( L"TERM" ) ); - - hash_init( &all_mappings, &hash_wcs_func, &hash_wcs_cmp ); - - /* - Add the default key bindings. - - Maybe some/most of these should be moved to the keybindings file? - */ - - /* - Many terminals (xterm, screen, etc.) have two different valid escape - sequences for arrow keys. One which is defined in terminfo/termcap - and one which is actually emitted by the arrow keys. The logic - escapes me, but I put in these hardcodes here for that reason. - */ - - add_common_bindings(); - add_emacs_bindings(); - add_vi_bindings(); - - current_mode_mappings = (array_list_t *)hash_get( &all_mappings, - L"emacs" ); - - - fn = env_get( L"INPUTRC" ); - - if( !fn ) - fn = L"~/.inputrc"; - fn = expand_tilde( wcsdup( fn )); + sb_clear( buff ); + sb_printf( buff, L"%s", res ); - if( fn ) - { - input_read_inputrc( fn ); - free(fn); - } - - current_application_mappings = (array_list_t *)hash_get( &all_mappings, - L"fish" ); - global_mappings = (array_list_t *)hash_get( &all_mappings, - L"global" ); - - return 1; - + return (wchar_t *)buff->buff; + } -/** - Free memory used by the specified mapping -*/ -static void destroy_mapping( void *key, void *val ) +const wchar_t *input_terminfo_get_name( const wchar_t *seq ) { - array_list_t *mappings = (array_list_t *)val; - - al_foreach( mappings, &free ); - al_destroy( mappings ); - - free((void *)key); - free((void *)val); -} + int i; + static string_buffer_t *buff = 0; - -void input_destroy() -{ - if( !is_init ) - return; - - is_init=0; - - input_common_destroy(); - - hash_foreach( &all_mappings, &destroy_mapping ); - hash_destroy( &all_mappings ); - - if( del_curterm( cur_term ) == ERR ) + CHECK( seq, 0 ); + input_init(); + + if( !buff ) { - debug( 0, _(L"Error while closing terminfo") ); + buff = sb_halloc( global_context ); } -} - -/** - Perform the action of the specified binding -*/ -static wint_t input_exec_binding( mapping *m, const wchar_t *seq ) -{ - int i; - -// fwprintf( stderr, L"Binding %ls\n", m->command ); - wchar_t code = input_get_code( m->command ); - if( code != -1 ) - { - switch( code ) - { - - case R_DUMP_FUNCTIONS: - { - for( i=0; i 0 && repeat <= 9 ) - repeat_count *= repeat; - - return R_REPAINT; - } - - case R_VI_DELETE_TO: - { - first_command = R_VI_DELETE_TO; - return R_REPAINT; - } - - default: - { - - if( first_command ) - { - switch( first_command ) - { - case R_VI_DELETE_TO: - { - - break; - - } - } - } - else - { - for( i=1; icommand, 0, TOP ); - - /* - We still need to return something to the caller, R_NULL - tells the reader that no key press needs to be handled, - and no repaint is needed. - - Bindings that produce output should emit a R_REPAINT - function by calling 'commandline -f repaint' to tell - fish that a repaint is in order. - */ + if( !m->seq ) + { + continue; + } - return R_NULL; + sb_clear( buff ); + sb_printf( buff, L"%s", m->seq ); + + if( !wcscmp( seq, (wchar_t *)buff->buff ) ) + { + return m->name; + } } + return 0; + } - - -/** - Try reading the specified function mapping -*/ -static wint_t input_try_mapping( mapping *m) +void input_terminfo_get_names( array_list_t *lst, int skip_null ) { - int j, k; - wint_t c=0; + int i; - c = input_common_readch( 0 ); - if( c == input_get_code( m->command ) ) - { - return input_exec_binding( m, m->seq ); - } - input_unreadch( c ); - - if( m->seq != 0 ) + CHECK( lst, ); + input_init(); + + for( i=0; iseq[j] != L'\0' && - m->seq[j] == (c=input_common_readch( j>0 )); j++ ) - ; + terminfo_mapping_t *m = (terminfo_mapping_t *)al_get( terminfo_mappings, i ); - if( m->seq[j] == L'\0' ) + if( skip_null && !m->seq ) { - return input_exec_binding( m, m->seq ); + continue; } - else - { - /* - Return the read characters - */ - input_unreadch(c); - for( k=j-1; k>=0; k-- ) - { - input_unreadch( m->seq[k] ); - } - } - } - return 0; - + al_push( lst, m->name ); + } } -void input_unreadch( wint_t ch ) +void input_function_get_names( array_list_t *lst ) { - input_common_unreadch( ch ); -} + int i; + CHECK( lst, ); + + for( i=0; i<(sizeof(name_arr)/sizeof(wchar_t *)); i++ ) + { + al_push( lst, name_arr[i] ); + } +} -wint_t input_readch() +wchar_t input_function_get_code( const wchar_t *name ) { - - int i; - CHECK_BLOCK( R_NULL ); - - /* - Clear the interrupted flag - */ - reader_interrupted(); - - /* - Search for sequence in various mapping tables - */ - - while( 1 ) + int i; + for( i = 0; i<(sizeof( code_arr )/sizeof(wchar_t)) ; i++ ) { - - if( current_application_mappings ) - { - for( i=0; iseq) == 0 ) - { - wchar_t arr[2]= - { - 0, - 0 - } - ; - arr[0] = input_common_readch(0); - - return input_exec_binding( m, arr ); - } + return code_arr[i]; } - - input_common_readch( 0 ); - - } + } + return -1; } + diff --git a/input.h b/input.h index 32406b28..575c34cb 100644 --- a/input.h +++ b/input.h @@ -99,26 +99,42 @@ void input_unreadch( wint_t ch ); \param d a description of the sequence \param cmd an input function that will be run whenever the key sequence occurs */ -void add_mapping( const wchar_t *mode, const wchar_t *s, const wchar_t * d, const wchar_t *cmd ); +void input_mapping_add( const wchar_t *sequence, const wchar_t *cmd ); + +void input_mapping_get_names( array_list_t *list ); + +int input_mapping_erase( const wchar_t *sequence ); + +const wchar_t *input_mapping_get( const wchar_t *sequence ); /** - Sets the mode keybindings. -*/ -void input_set_mode( wchar_t *name ); + Return the sequence for the terminfo variable of the specified name. + + If no terminfo variable of the specified name could be found, return 0 and set errno to ENOENT. + If the terminfo variable does not have a value, return 0 and set errno to EILSEQ. + */ +const wchar_t *input_terminfo_get_sequence( const wchar_t *name ); /** - Sets the application keybindings -*/ -void input_set_application( wchar_t *name ); + Return the name of the terminfo variable with the specified sequence + */ +const wchar_t *input_terminfo_get_name( const wchar_t *seq ); /** - Parse a single line of inputrc information. -*/ -void input_parse_inputrc_line( wchar_t *cmd ); + Return a list of all known terminfo names + */ +void input_terminfo_get_names( array_list_t *lst, int skip_null ); + /** - Returns the function for the given function name. + Returns the input function code for the given input function name. */ -wchar_t input_get_code( const wchar_t *name ); +wchar_t input_function_get_code( const wchar_t *name ); + +/** + Returns a list of all existing input function names + */ +void input_function_get_names( array_list_t *lst ); + #endif diff --git a/share/completions/bind.fish b/share/completions/bind.fish index 0a4f23fd..a987d3c0 100644 --- a/share/completions/bind.fish +++ b/share/completions/bind.fish @@ -1,3 +1,12 @@ +complete -c bind -s a -l all --description 'Show unavaliable key bindings/erase all bindings' +complete -c bind -s e -l erase --description 'Erase mode' +complete -c bind -s f -l function-names --description 'Print names of available functions' complete -c bind -s h -l help --description "Display help and exit" -complete -c bind -s M -l set-mode --description 'Change input mode' +complete -c bind -s k -l key --description 'Specify key name, not sequence' +complete -c bind -s K -l key-names --description 'Print names of available keys' + +complete -c bind -n __fish_bind_test1 -a '(bind --key-names)' -d 'Key name' -x +complete -c bind -n __fish_bind_test2 -a '(bind --function-names)' -d 'Function name' -x + + diff --git a/share/functions/__fish_bind_test1.fish b/share/functions/__fish_bind_test1.fish new file mode 100644 index 00000000..37f5eeb0 --- /dev/null +++ b/share/functions/__fish_bind_test1.fish @@ -0,0 +1,27 @@ + +function __fish_bind_test1 + +set -l args +set -l use_keys no +for i in (commandline -poc) + switch $i + case -k --k --ke --key + set use_keys yes + + case "-*" + + case "*" + set args $args $i + end +end + +switch $use_keys + case yes + switch (count $args) + case 1 + return 0 + end +end +return 1 + +end diff --git a/share/functions/__fish_bind_test2.fish b/share/functions/__fish_bind_test2.fish new file mode 100644 index 00000000..8530451c --- /dev/null +++ b/share/functions/__fish_bind_test2.fish @@ -0,0 +1,20 @@ + +function __fish_bind_test2 +set -l args +for i in (commandline -poc) + switch $i + case "-*" + + case "*" + set args $args $i + end +end + + switch (count $args) + case 2 + return 0 + end + + return 1 + +end diff --git a/share/functions/__fish_config_interactive.fish b/share/functions/__fish_config_interactive.fish index 6e100fdc..ce51a01b 100644 --- a/share/functions/__fish_config_interactive.fish +++ b/share/functions/__fish_config_interactive.fish @@ -99,24 +99,6 @@ function __fish_config_interactive -d "Initializations that should be performed printf (_ "Good bye\n") end - # - # Set INPUTRC to something nice - # - # We override INPUTRC if already set, since it may be set by a shell - # other than fish, which may use a different file. The new value should - # be exported, since the fish inputrc file plays nice with other files - # by including them when found. - # - - for i in $configdir/fish/fish_inputrc $__fish_sysconfdir/fish_inputrc ~/.inputrc /etc/inputrc - if test -f $i - set -xg INPUTRC $i - break - end - end - - - # # Set various defaults using these throwaway functions # @@ -202,5 +184,16 @@ function __fish_config_interactive -d "Initializations that should be performed complete -x -p "/etc/init.d/*" -a status --description 'Print service status' complete -x -p "/etc/init.d/*" -a restart --description 'Stop and then start service' complete -x -p "/etc/init.d/*" -a reload --description 'Reload service configuration' + + if not set -q fish_key_bindings + set -U fish_key_bindings fish_default_key_bindings + end + + eval $fish_key_bindings + function __fish_reload_key_bindings -d "Reload keybindings when binding variable change" + eval $fish_key_bindings + end end + + diff --git a/share/functions/fish_default_key_bindings.fish b/share/functions/fish_default_key_bindings.fish new file mode 100644 index 00000000..8db6d803 --- /dev/null +++ b/share/functions/fish_default_key_bindings.fish @@ -0,0 +1,91 @@ + +function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fish" + + # Clear earlier bindings, if any + bind --erase --all + + # This is the default binding, i.e. the one used if no other binding matches + bind "" self-insert + + bind \n execute + + bind \ck kill-line + bind \cy yank + bind \t complete + + bind \e\n "commandline -i \n" + + bind \e\[A up-or-search + bind \e\[B down-or-search + bind -k down down-or-search + bind -k up up-or-search + + bind \e\[C forward-char + bind \e\[D backward-char + bind -k right forward-char + bind -k left backward-char + + bind -k dc delete-char + bind -k backspace backward-delete-char + bind \x7f backward-delete-char + + bind \e\[H beginning-of-line + bind \e\[F end-of-line + bind -k home beginning-of-line + bind -k end end-of-line + + bind \e\eOC nextd-or-forward-word + bind \e\eOD prevd-or-backward-word + bind \e\e\[C nextd-or-forward-word + bind \e\e\[D prevd-or-backward-word + bind \eO3C nextd-or-forward-word + bind \eO3D prevd-or-backward-word + bind \e\[3C nextd-or-forward-word + bind \e\[3D prevd-or-backward-word + bind \e\[1\;3C nextd-or-forward-word + bind \e\[1\;3D prevd-or-backward-word + + bind \e\eOA history-token-search-backward + bind \e\eOB history-token-search-forward + bind \e\e\[A history-token-search-backward + bind \e\e\[B history-token-search-forward + bind \eO3A history-token-search-backward + bind \eO3B history-token-search-forward + bind \e\[3A history-token-search-backward + bind \e\[3B history-token-search-forward + bind \e\[1\;3A history-token-search-backward + bind \e\[1\;3B history-token-search-forward + + bind \ca beginning-of-line + bind \ce end-of-line + bind \ey yank-pop + bind \ch backward-delete-char + bind \cw backward-kill-word + bind \cp history-search-backward + bind \cn history-search-forward + bind \cf forward-char + bind \cb backward-char + bind \e\x7f backward-kill-word + bind \eb backward-word + bind \ef forward-word + bind \ed forward-kill-word + bind -k ppage beginning-of-history + bind -k npage end-of-history + bind \e\< beginning-of-buffer + bind \e\> end-of-buffer + + bind \el __fish_list_current_token + bind \ew 'set tok (commandline -pt); if test $tok[1]; whatis $tok[1]; commandline -f repaint; end' + bind \cl 'clear; commandline -f repaint' + bind \cc delete-line + bind \cu backward-kill-line + bind \ed kill-word + bind \cw backward-kill-word + bind \ed 'if test -z (commandline); dirh; commandline -f repaint; else; commandline -f kill-word; end' + bind \cd delete-or-exit + + # This will make sure the output of the current command is paged using the less pager when you press Meta-p + bind \ep 'if commandline -j|grep -v "less *\$" >/dev/null; commandline -aj "|less;"; end' + +end + -- cgit v1.2.3