diff options
Diffstat (limited to 'input.c')
-rw-r--r-- | input.c | 1562 |
1 files changed, 294 insertions, 1268 deletions
@@ -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 */ @@ -225,67 +238,23 @@ 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,1064 +292,33 @@ 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; - - if( mode == 0 ) - return; - - mappings = get_mapping( mode ); - - for( i=0; i<al_get_count( mappings); i++ ) - { - mapping *m = (mapping *)al_get( mappings, i ); - if( wcscmp( m->seq, s ) == 0 ) - { - m->seq_desc = intern(d); - m->command = intern(c); - return; - } - } - - mapping *m = malloc( sizeof( mapping ) ); - m->seq = intern( s ); - m->seq_desc = intern(d ); - m->command = intern(c); - al_push( mappings, m ); -} - -/** - Compare sort order for two keyboard mappings. This function is made - to be suitable for use with the qsort method. -*/ -/* -static int mapping_compare( const void *a, const void *b ) -{ - 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 ); + CHECK( sequence, ); + CHECK( command, ); -} -*/ - - -/** - 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 i; - fwprintf( stdout, L"\n" ); - - qsort(current_mappings.arr, - al_get_count( &mappings), - sizeof( void*), - &mapping_compare ); + // debug( 0, L"Add mapping from %ls to %ls", escape(sequence, 1), escape(command, 1 ) ); - for( i=0; i<al_get_count( &mappings ); i++ ) - { - mapping *m = (mapping *)al_get( &mappings, i ); - -// write_sequence( m->seq ); -fwprintf( stdout, -L"%ls: %ls\n", -m->seq_desc, -m->command ); -} -repaint();*/ -} - - -/** - Parse special character from the specified inputrc-style key binding. - - Control-a is expanded to 1, etc. -*/ - -static wchar_t *input_symbolic_sequence( const wchar_t *in ) -{ - wchar_t *res=0; - - if( !*in || *in == L'\n' ) - return 0; - - 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 + for( i=0; i<al_get_count( &mappings); i++ ) { - int i; - struct + input_mapping_t *m = (input_mapping_t *)al_get( &mappings, i ); + if( wcscmp( m->seq, sequence ) == 0 ) { - 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; - } - } - - 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; - } - - wchar_t *res2 = input_symbolic_sequence( in ); - if( !res2 ) - { - free( res ); - return 0; - } - wchar_t *res3 = wcsdupcat( res, res2 ); - free( res); - free(res2); - - return res3; -} - -/** - Unescape special character from the specified inputrc-style key sequence. - - \\C-a is expanded to 1, etc. -*/ -static wchar_t *input_expand_sequence( const wchar_t *in ) -{ - 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 ) - { - 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<chars; i++ ) - { - int d = convert_digit( *in++, base); - if( d < 0 ) - { - break; - } - - res=(res*base)|d; - - } - in--; - - debug( 4, - L"Got numeric key sequence %d", - res ); - - *(out++) = res; - break; - } - - /* - Parse control sequence - */ - case L'C': - { - int has_escape = 0; - - in++; - /* Make sure next key is a dash*/ - if( *in != L'-' ) - { - error=1; - debug( 1, _( L"Invalid sequence - no dash after control\n" ) ); - break; - } - in++; - - if( (*in == L'\\') && (*(in+1)==L'e') ) - { - has_escape = 1; - in += 2; - - } - - - if( (*in >= 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; - } - default: - { - *(out++)=*in; - break; - } - } - 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; - } - } - - 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' ') ) - { - *p=L'\0'; - p--; - } - - /* Skip comments */ - if( *cmd == L'#' ) - return; - - /* Skip empty lines */ - if( *cmd == L'\0' ) - return; - - if( wcscmp( L"$endif", cmd) == 0 ) - { - if( inputrc_skip_block_count ) - { - inputrc_skip_block_count--; -/* - if( !inputrc_skip_block_count ) - fwprintf( stderr, L"Stop skipping\n" ); - else - fwprintf( stderr, L"Decrease skipping\n" ); -*/ - } - 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 ) - { - inputrc_skip_block_count--; - inputrc_block_count++; - } - - } - 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; - } - - if( *cmd == L'\"' ) - { - - wchar_t *key; - wchar_t *val; - wchar_t *sequence; - wchar_t prev=0; - - - 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; + m->command = intern(command); 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 ); - - 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 ) - { - 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 - { -// fwprintf( stderr, L"Conditional %ls is false\n", cmd ); - inputrc_skip_block_count++; - } - free( term_line ); - free( term_line2 ); - - return; - } - else - { - /* - This is a redular key binding, like - - Control-o: kill-word - - Or at least we hope it is, since if it isn't, we have no idea what it is. - */ - - wchar_t *key; - wchar_t *val; - wchar_t *sequence; - - key=cmd; - - cmd = wcschr( cmd, ':' ); - - if( !cmd ) - { - debug( 1, - _( L"Unable to parse key binding" ) ); - inputrc_error = 1; - return; - } - *cmd = 0; - - cmd++; - - while( *cmd == L' ' ) - cmd++; - - val = cmd; - - debug( 3, L"Map %ls to %ls\n", key, val ); - - sequence = input_symbolic_sequence( key ); - if( sequence ) - { - add_mapping( L"global", sequence, key, val ); - free( sequence ); - } - - return; - - } - - debug( 1, _( L"I don\'t know what %ls means" ), cmd ); -} - -/** - Read the specified inputrc file -*/ -static void input_read_inputrc( wchar_t *fn ) -{ - 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" ); - - if( rc ) - { - while( !feof( rc ) && (!error)) - { - switch( fgetws2( &buff, &buff_len, rc ) ) - { - 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; - } - } - } - } - free( buff ); - /* - Don't need to check exit status of fclose on read-only stream - */ - fclose( rc ); - } - signal_unblock(); - - 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 ) -{ - if( seq ) - { - wchar_t *tmp; - tmp=str2wcs(seq); - if( tmp ) - { - add_mapping( mode, tmp, desc, func ); - free(tmp); - } - } - -} - -/** - 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 ) -{ - wchar_t *esc = input_expand_sequence( seq ); - if( esc ) - { - add_mapping( mode, esc, desc, func ); - free(esc); - } -} - -/** - Add bindings common to emacs and vi -*/ -static void add_common_bindings() -{ - static const wchar_t *name[] = - { - L"emacs", - L"vi", - L"vi-command" - } - ; - int i; - - /* - Universal bindings - */ - for( i=0; i<3; i++ ) - { - 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" ); } - - /* - 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") -*/ + input_mapping_t *m = malloc( sizeof( input_mapping_t ) ); + m->seq = intern( sequence ); + m->command = intern(command); + al_push( &mappings, m ); } @@ -1425,8 +363,6 @@ static int interrupt_handler() int input_init() { - wchar_t *fn; - if( is_init ) return 1; @@ -1441,177 +377,67 @@ int input_init() } 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"; + input_terminfo_init(); - fn = expand_tilde( wcsdup( fn )); - 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; - } -/** - Free memory used by the specified mapping -*/ -static void destroy_mapping( void *key, void *val ) -{ - array_list_t *mappings = (array_list_t *)val; - - al_foreach( mappings, &free ); - al_destroy( mappings ); - - free((void *)key); - free((void *)val); -} - - void input_destroy() { if( !is_init ) return; + is_init=0; + al_foreach( &mappings, &free ); + al_destroy( &mappings ); + input_common_destroy(); - hash_foreach( &all_mappings, &destroy_mapping ); - hash_destroy( &all_mappings ); - if( del_curterm( cur_term ) == ERR ) { debug( 0, _(L"Error while closing terminfo") ); } + + input_terminfo_destroy(); } /** Perform the action of the specified binding */ -static wint_t input_exec_binding( mapping *m, const wchar_t *seq ) +static wint_t input_exec_binding( input_mapping_t *m, const wchar_t *seq ) { - int i; - -// fwprintf( stderr, L"Binding %ls\n", m->command ); - wchar_t code = input_get_code( m->command ); + wchar_t code = input_function_get_code( m->command ); if( code != -1 ) { switch( code ) { - case R_DUMP_FUNCTIONS: - { - for( i=0; i<repeat_count; i++ ) - dump_functions(); - repeat_count = 1; - return R_REPAINT; - } - case R_SELF_INSERT: { - int idx = 0; - - if( seq[0] == L'\x1b' && seq[1] ) - { - idx = 1; - } - - for( i=1; i<repeat_count; i++ ) - input_unreadch( seq[idx] ); - repeat_count = 1; - return seq[idx]; - } - - case R_VI_ARG_DIGIT: - { - int repeat = seq[0]-L'0'; - if( repeat > 0 && repeat <= 9 ) - repeat_count *= repeat; - - return R_REPAINT; + return seq[0]; } - 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; i<repeat_count; i++ ) - { - input_unreadch( code ); - } - } - - repeat_count = 1; - first_command = 0; return code; } - } + } } else { - + /* 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, @@ -1623,8 +449,8 @@ static wint_t input_exec_binding( mapping *m, const wchar_t *seq ) */ return R_NULL; + } - } @@ -1632,13 +458,16 @@ static wint_t input_exec_binding( mapping *m, const wchar_t *seq ) /** Try reading the specified function mapping */ -static wint_t input_try_mapping( mapping *m) +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_get_code( m->command ) ) + if( c == input_function_get_code( m->command ) ) { return input_exec_binding( m, m->seq ); } @@ -1646,8 +475,9 @@ static wint_t input_try_mapping( mapping *m) if( m->seq != 0 ) { + for( j=0; m->seq[j] != L'\0' && - m->seq[j] == (c=input_common_readch( j>0 )); j++ ) + m->seq[j] == (c=input_common_readch( j>0 )); j++ ) ; if( m->seq[j] == L'\0' ) @@ -1665,7 +495,7 @@ static wint_t input_try_mapping( mapping *m) input_unreadch( m->seq[k] ); } } - } + } return 0; } @@ -1675,7 +505,6 @@ void input_unreadch( wint_t ch ) input_common_unreadch( ch ); } - wint_t input_readch() { @@ -1687,51 +516,27 @@ wint_t input_readch() Clear the interrupted flag */ reader_interrupted(); - + /* Search for sequence in various mapping tables */ while( 1 ) { - - if( current_application_mappings ) - { - for( i=0; i<al_get_count( current_application_mappings); i++ ) - { - wint_t res = input_try_mapping( (mapping *)al_get( current_application_mappings, i )); - if( res ) - return res; - } - } - - if( global_mappings ) + for( i=0; i<al_get_count( &mappings); i++ ) { - for( i=0; i<al_get_count( global_mappings); i++ ) - { - wint_t res = input_try_mapping( (mapping *)al_get( global_mappings, i )); - if( res ) - return res; - } - } - - if( current_mode_mappings ) - { - for( i=0; i<al_get_count( current_mode_mappings); i++ ) - { - wint_t res = input_try_mapping( (mapping *)al_get( current_mode_mappings, i )); - if( res ) - return res; - } + wint_t res = input_try_mapping( (input_mapping_t *)al_get( &mappings, i )); + if( res ) + return res; } /* - No matching exact mapping, try to find the generic mapping. + No matching exact mapping, try to find generic mapping. */ - for( i=0; i<al_get_count( current_mode_mappings); i++ ) + for( i=0; i<al_get_count( &mappings); i++ ) { - mapping *m = (mapping *)al_get( current_mode_mappings, i ); + input_mapping_t *m = (input_mapping_t *)al_get( &mappings, i ); if( wcslen( m->seq) == 0 ) { wchar_t arr[2]= @@ -1746,7 +551,228 @@ wint_t input_readch() } } + /* + No action to take on specified character, ignoer it + and move to next one. + */ input_common_readch( 0 ); } } + +void input_mapping_get_names( array_list_t *list ) +{ + int i; + + for( i=0; i<al_get_count( &mappings ); i++ ) + { + input_mapping_t *m = (input_mapping_t *)al_get( &mappings, i ); + al_push( list, m->seq ); + } + +} + + +int input_mapping_erase( const wchar_t *sequence ) +{ + int ok = 0; + int i; + size_t sz = al_get_count( &mappings ); + + for( i=0; i<sz; i++ ) + { + input_mapping_t *m = (input_mapping_t *)al_get( &mappings, i ); + if( !wcscmp( sequence, m->seq ) ) + { + if( i != (sz-1 ) ) + { + al_set( &mappings, i, al_get( &mappings, sz -1 ) ); + } + al_truncate( &mappings, sz-1 ); + ok = 1; + + free( m ); + + break; + + } + + } + + return ok; + +} + +const wchar_t *input_mapping_get( const wchar_t *sequence ) +{ + int i; + size_t sz = al_get_count( &mappings ); + + for( i=0; i<sz; i++ ) + { + input_mapping_t *m = (input_mapping_t *)al_get( &mappings, i ); + if( !wcscmp( sequence, m->seq ) ) + { + return m->command; + } + } + return 0; +} +/** + Add all terminfo mappings + */ +static void input_terminfo_init() +{ + 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 ); +} + +static void input_terminfo_destroy() +{ + + if( terminfo_mappings ) + { + halloc_free( terminfo_mappings ); + } +} + +const wchar_t *input_terminfo_get_sequence( const wchar_t *name ) +{ + const char *res = 0; + int i; + static string_buffer_t *buff = 0; + int err = ENOENT; + + CHECK( name, 0 ); + input_init(); + + for( i=0; i<al_get_count( terminfo_mappings ); i++ ) + { + terminfo_mapping_t *m = (terminfo_mapping_t *)al_get( terminfo_mappings, i ); + + if( !wcscmp( name, m->name ) ) + { + res = m->seq; + err = EILSEQ; + break; + } + } + + if( !res ) + { + errno = err; + return 0; + } + + if( !buff ) + { + buff = sb_halloc( global_context ); + } + + sb_clear( buff ); + sb_printf( buff, L"%s", res ); + + return (wchar_t *)buff->buff; + +} + +const wchar_t *input_terminfo_get_name( const wchar_t *seq ) +{ + int i; + static string_buffer_t *buff = 0; + + CHECK( seq, 0 ); + input_init(); + + if( !buff ) + { + buff = sb_halloc( global_context ); + } + + for( i=0; i<al_get_count( terminfo_mappings ); i++ ) + { + terminfo_mapping_t *m = (terminfo_mapping_t *)al_get( terminfo_mappings, i ); + + if( !m->seq ) + { + continue; + } + + sb_clear( buff ); + sb_printf( buff, L"%s", m->seq ); + + if( !wcscmp( seq, (wchar_t *)buff->buff ) ) + { + return m->name; + } + } + + return 0; + +} + +void input_terminfo_get_names( array_list_t *lst, int skip_null ) +{ + int i; + + CHECK( lst, ); + input_init(); + + for( i=0; i<al_get_count( terminfo_mappings ); i++ ) + { + terminfo_mapping_t *m = (terminfo_mapping_t *)al_get( terminfo_mappings, i ); + + if( skip_null && !m->seq ) + { + continue; + } + al_push( lst, m->name ); + } +} + +void input_function_get_names( array_list_t *lst ) +{ + int i; + + CHECK( lst, ); + + for( i=0; i<(sizeof(name_arr)/sizeof(wchar_t *)); i++ ) + { + al_push( lst, name_arr[i] ); + } +} + +wchar_t input_function_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; +} + |