aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar liljencrantz <liljencrantz@gmail.com>2007-09-26 02:14:47 +1000
committerGravatar liljencrantz <liljencrantz@gmail.com>2007-09-26 02:14:47 +1000
commitcf8e746d0c04aec16df8e69d2987c785cb510d46 (patch)
treef20053b4e7370efc11e6c8277e2a220b7a386e69
parentaf9c2067e1fecb10ab7540e7f7682211448b81c0 (diff)
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
-rw-r--r--builtin.c254
-rw-r--r--builtin_commandline.c2
-rw-r--r--doc_src/bind.txt48
-rw-r--r--etc/fish_inputrc28
-rw-r--r--input.c1562
-rw-r--r--input.h40
-rw-r--r--share/completions/bind.fish11
-rw-r--r--share/functions/__fish_bind_test1.fish27
-rw-r--r--share/functions/__fish_bind_test2.fish20
-rw-r--r--share/functions/__fish_config_interactive.fish29
-rw-r--r--share/functions/fish_default_key_bindings.fish91
11 files changed, 755 insertions, 1357 deletions
diff --git a/builtin.c b/builtin.c
index cd412bdb..6b0b9979 100644
--- a/builtin.c
+++ b/builtin.c
@@ -402,22 +402,169 @@ 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; i<al_get_count(&lst); i++ )
+ {
+ wchar_t *seq = (wchar_t *)al_get( &lst, i );
+
+ const wchar_t *tname = input_terminfo_get_name( seq );
+ wchar_t *ecmd = escape( input_mapping_get( seq ), 1 );
+
+ if( tname )
+ {
+ sb_printf( sb_out, L"bind -k %ls %ls\n", tname, ecmd );
+ }
+ else
+ {
+ wchar_t *eseq = escape( seq, 1 );
+
+ sb_printf( sb_out, L"bind %ls %ls\n", eseq, ecmd );
+ free( eseq );
+ }
+
+ free( ecmd );
+
+ }
+
+ al_destroy( &lst );
+}
+
+static void builtin_bind_key_names( int all )
+{
+ array_list_t lst;
+ int i;
+
+ al_init( &lst );
+ input_terminfo_get_names( &lst, !all );
+
+ for( i=0; i<al_get_count(&lst); i++ )
+ {
+ wchar_t *seq = (wchar_t *)al_get( &lst, i );
+
+ sb_printf( sb_out, L"%ls\n", seq );
+ }
+
+ al_destroy( &lst );
+}
+
+static void builtin_bind_function_names()
+{
+ array_list_t lst;
+ int i;
+
+ al_init( &lst );
+ input_function_get_names( &lst );
+
+ for( i=0; i<al_get_count(&lst); i++ )
+ {
+ wchar_t *seq = (wchar_t *)al_get( &lst, i );
+
+ sb_printf( sb_out, L"%ls\n", seq );
+ }
+
+ al_destroy( &lst );
+}
+
+static int builtin_bind_add( wchar_t *seq, wchar_t *cmd, int terminfo )
+{
+
+ if( terminfo )
+ {
+ const wchar_t *seq2 = input_terminfo_get_sequence( seq );
+ if( seq2 )
+ {
+ input_mapping_add( seq2, cmd );
+ }
+ else
+ {
+ return 1;
+ }
+
+ }
+ else
+ {
+ input_mapping_add( seq, cmd );
+ }
+
+ return 0;
+
+}
+
+static void builtin_bind_erase( wchar_t **seq, int all )
+{
+ if( all )
+ {
+ int i;
+ array_list_t lst;
+ al_init( &lst );
+
+ input_mapping_get_names( &lst );
+
+ for( i=0; i<al_get_count( &lst ); i++ )
+ {
+ input_mapping_erase( (wchar_t *)al_get( &lst, i ) );
+ }
+
+ al_destroy( &lst );
+ }
+ else
+ {
+ while( *seq )
+ {
+ input_mapping_erase( *seq++ );
+ }
+
+ }
+
+}
+
/**
The bind builtin, used for setting character sequences
*/
static int builtin_bind( wchar_t **argv )
{
+
+ enum
+ {
+ BIND_INSERT,
+ BIND_ERASE,
+ BIND_KEY_NAMES,
+ BIND_FUNCTION_NAMES
+ }
+ ;
+
int i;
int argc=builtin_count_args( argv );
-
+ int mode = BIND_INSERT;
+ int res = STATUS_BUILTIN_OK;
+ int all = 0;
+
+ int use_terminfo = 0;
+
woptind=0;
const static struct woption
long_options[] =
{
{
- L"set-mode", required_argument, 0, 'M'
+ L"all", no_argument, 0, 'a'
+ }
+ ,
+ {
+ L"erase", no_argument, 0, 'e'
+ }
+ ,
+ {
+ L"function-names", no_argument, 0, 'f'
}
,
{
@@ -425,6 +572,14 @@ static int builtin_bind( wchar_t **argv )
}
,
{
+ L"key", no_argument, 0, 'k'
+ }
+ ,
+ {
+ L"key-names", no_argument, 0, 'K'
+ }
+ ,
+ {
0, 0, 0, 0
}
}
@@ -433,15 +588,15 @@ static int builtin_bind( wchar_t **argv )
while( 1 )
{
int opt_index = 0;
-
int opt = wgetopt_long( argc,
- argv,
- L"M:h",
- long_options,
- &opt_index );
+ argv,
+ L"aehkKf",
+ long_options,
+ &opt_index );
+
if( opt == -1 )
break;
-
+
switch( opt )
{
case 0:
@@ -455,28 +610,97 @@ static int builtin_bind( wchar_t **argv )
return STATUS_BUILTIN_ERROR;
- case 'M':
- input_set_mode( woptarg );
+ case 'a':
+ all = 1;
break;
+
+ case 'e':
+ mode = BIND_ERASE;
+ break;
+
case 'h':
builtin_print_help( argv[0], sb_out );
return STATUS_BUILTIN_OK;
+ case 'k':
+ use_terminfo = 1;
+ break;
+
+ case 'K':
+ mode = BIND_KEY_NAMES;
+ break;
+
+ case 'f':
+ mode = BIND_FUNCTION_NAMES;
+ break;
+
case '?':
builtin_unknown_option( argv[0], argv[woptind-1] );
return STATUS_BUILTIN_ERROR;
}
-
+
}
- for( i=woptind; i<argc; i++ )
+ switch( mode )
{
- input_parse_inputrc_line( argv[i] );
- }
+
+ case BIND_ERASE:
+ {
+ builtin_bind_erase( &argv[woptind], all);
+ break;
+ }
+
+ case BIND_INSERT:
+ {
+ switch( argc-woptind )
+ {
+ case 0:
+ {
+ builtin_bind_list();
+ break;
+ }
- return STATUS_BUILTIN_OK;
+ case 2:
+ {
+ builtin_bind_add(argv[woptind], argv[woptind+1], use_terminfo );
+ break;
+ }
+
+ default:
+ {
+ res = STATUS_BUILTIN_ERROR;
+ sb_printf( sb_err, _(L"%ls: Expected zero or two parameters, got %d"), argv[0], argc-woptind );
+ break;
+ }
+ }
+ break;
+ }
+
+ case BIND_KEY_NAMES:
+ {
+ builtin_bind_key_names( all );
+ break;
+ }
+
+
+ case BIND_FUNCTION_NAMES:
+ {
+ builtin_bind_function_names();
+ break;
+ }
+
+
+ default:
+ {
+ res = STATUS_BUILTIN_ERROR;
+ sb_printf( sb_err, _(L"%ls: Invalid state\n"), argv[0] );
+ break;
+ }
+ }
+
+ return res;
}
/**
diff --git a/builtin_commandline.c b/builtin_commandline.c
index d2769681..82d92966 100644
--- a/builtin_commandline.c
+++ b/builtin_commandline.c
@@ -448,7 +448,7 @@ static int builtin_commandline( wchar_t **argv )
}
for( i=woptind; i<argc; i++ )
{
- wint_t c = input_get_code( argv[i] );
+ wint_t c = input_function_get_code( argv[i] );
if( c != -1 )
{
/*
diff --git a/doc_src/bind.txt b/doc_src/bind.txt
index 13f22f38..e899b0bd 100644
--- a/doc_src/bind.txt
+++ b/doc_src/bind.txt
@@ -1,23 +1,43 @@
-\section bind bind - handle key bindings
+\section bind bind - handle fish key bindings
\subsection bind-synopsis Synopsis
-<tt>bind [OPTIONS] [BINDINGS...]</tt>
+<tt>bind [OPTIONS] SEQUENCE COMMAND</tt>
-The <tt>bind</tt> builtin causes fish to add the readline style bindings specified by BINDINGS to the list of key bindings, as if they appeared in your <tt>~/.fish_inputrc</tt> file.
+\subsection bind-description Description
-For more information on the syntax keyboard bindings, use <tt>man
-readline</tt> to access the readline documentation. The available commands
-are listed in the <a href="index.html#editor">Command Line Editor</a> section
-of the fish manual - but you may also use any fish command! To write such
-commands, see the <a href="#commandline">commandline</a> builtin. It's good
-practice to put the code into a <tt><a href="#function">function</a> -b</tt>
-and bind to the function name.
+The <tt>bind</tt> 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 <tt>\\ew</tt>, and Control-x can be written as
+<tt>\\cx</tt>.
+
+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 <tt>bind
+--names</tt> 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 <a href="#function">function</a> and simply
+bind to the function name.
+
+- <tt>-a</tt> or <tt>--all</tt> 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.
+- <tt>-e</tt> or <tt>--erase</tt> Erase mode. All non-switch arguments are interpreted as character sequences and any commands associated with those sequences are erased.
+- <tt>-h</tt> or <tt>--help</tt> Display help and exit
+- <tt>-k</tt> or <tt>--key</tt> Specify a key name, such as 'left' or 'backspace' instead of a character sequence
+- <tt>-K</tt> or <tt>--key-names</tt> Display a list of available key names
+- <tt>-f</tt> or <tt>--function-names</tt> Display a list of available input functions
-\subsection bind-description Description
-- <tt>-M MODE</tt> or <tt>--set-mode=MODE</tt> sets the current input mode to MODE.
\subsection bind-example Example
-<tt>bind -M vi</tt> changes to the vi input mode
+<tt>bind \cd 'exit'</tt> causes fish to exit on Control-d
+
+<tt>bind -k ppage history-search-backward</tt> Causes fish to perform a history search when the page up key is pressed
-<tt>bind '"\\M-j": jobs'</tt> 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
*/
@@ -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;
+}
+
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
@@ -100,24 +100,6 @@ function __fish_config_interactive -d "Initializations that should be performed
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
+