From d2d397d9eb8ec9c4003d1ce45b26a7cc133e801f Mon Sep 17 00:00:00 2001 From: liljencrantz Date: Sat, 22 Sep 2007 00:05:49 +1000 Subject: [PATCH] Make up/down cursor move up or down when in multiline mode, except if already in search mode or at the top/bottom line. Since part of this is done in script-space, this involves adding some functionality to the commandline builtin. darcs-hash:20070921140549-75c98-ba9e83f5e6fdecae5df8f83dd863794c6af9770c.gz --- builtin_commandline.c | 46 +++++++++-- input.c | 16 ++-- input.h | 4 +- parse_util.c | 91 ++++++++++++++++++++++ parse_util.h | 17 ++++ reader.c | 115 ++++++++++++++++++++++++---- reader.h | 8 ++ share/functions/down-or-search.fish | 23 ++++++ share/functions/up-or-search.fish | 17 ++++ 9 files changed, 308 insertions(+), 29 deletions(-) create mode 100644 share/functions/down-or-search.fish create mode 100644 share/functions/up-or-search.fish diff --git a/builtin_commandline.c b/builtin_commandline.c index 3d6b4451b..d27696817 100644 --- a/builtin_commandline.c +++ b/builtin_commandline.c @@ -220,6 +220,8 @@ static int builtin_commandline( wchar_t **argv ) int tokenize = 0; int cursor_mode = 0; + int line_mode = 0; + int search_mode = 0; wchar_t *begin, *end; current_buffer = (wchar_t *)builtin_complete_get_temporary_buffer(); @@ -312,6 +314,14 @@ static int builtin_commandline( wchar_t **argv ) L"cursor", no_argument, 0, 'C' } , + { + L"line", no_argument, 0, 'L' + } + , + { + L"search-mode", no_argument, 0, 'S' + } + , { 0, 0, 0, 0 } @@ -322,7 +332,7 @@ static int builtin_commandline( wchar_t **argv ) int opt = wgetopt_long( argc, argv, - L"abijpctwforhI:C", + L"abijpctwforhI:CLS", long_options, &opt_index ); if( opt == -1 ) @@ -391,6 +401,14 @@ static int builtin_commandline( wchar_t **argv ) cursor_mode = 1; break; + case 'L': + line_mode = 1; + break; + + case 'S': + search_mode = 1; + break; + case 'h': builtin_print_help( argv[0], sb_out ); return 0; @@ -408,7 +426,7 @@ static int builtin_commandline( wchar_t **argv ) /* Check for invalid switch combinations */ - if( buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode ) + if( buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode || search_mode ) { sb_printf(sb_err, BUILTIN_ERR_COMBO, @@ -457,7 +475,7 @@ static int builtin_commandline( wchar_t **argv ) /* Check for invalid switch combinations */ - if( cursor_mode && (argc-woptind > 1) ) + if( (search_mode || line_mode || cursor_mode) && (argc-woptind > 1) ) { sb_append2( sb_err, @@ -468,7 +486,7 @@ static int builtin_commandline( wchar_t **argv ) return 1; } - if( (buffer_part || tokenize || cut_at_cursor) && cursor_mode ) + if( (buffer_part || tokenize || cut_at_cursor) && (cursor_mode || line_mode || search_mode) ) { sb_printf( sb_err, BUILTIN_ERR_COMBO, @@ -527,9 +545,9 @@ static int builtin_commandline( wchar_t **argv ) if( *endptr || errno ) { sb_printf( sb_err, - BUILTIN_ERR_NOT_NUMBER, - argv[0], - argv[woptind] ); + BUILTIN_ERR_NOT_NUMBER, + argv[0], + argv[woptind] ); builtin_print_help( argv[0], sb_err ); } @@ -546,6 +564,20 @@ static int builtin_commandline( wchar_t **argv ) } + if( line_mode ) + { + int pos = reader_get_cursor_pos(); + wchar_t *buff = reader_get_buffer(); + sb_printf( sb_out, L"%d\n", parse_util_lineno( buff, pos ) ); + return 0; + + } + + if( search_mode ) + { + return !reader_search_mode(); + } + switch( buffer_part ) { diff --git a/input.c b/input.c index 0c5838581..e4b7c314f 100644 --- a/input.c +++ b/input.c @@ -134,7 +134,9 @@ static const wchar_t *name_arr[] = L"execute", L"beginning-of-buffer", L"end-of-buffer", - L"repaint" + L"repaint", + L"up-line", + L"down-line" } ; @@ -215,7 +217,9 @@ static const wchar_t code_arr[] = R_EXECUTE, R_BEGINNING_OF_BUFFER, R_END_OF_BUFFER, - R_REPAINT + R_REPAINT, + R_UP_LINE, + R_DOWN_LINE } ; @@ -1242,10 +1246,10 @@ static void add_common_bindings() terminfo sometimes specifies a different sequence than what keypresses actually generate */ - add_mapping( name[i], L"\x1b[A", L"Up", L"history-search-backward" ); - add_mapping( name[i], L"\x1b[B", L"Down", L"history-search-forward" ); - add_terminfo_mapping( name[i], (key_up), L"Up", L"history-search-backward" ); - add_terminfo_mapping( name[i], (key_down), L"Down", L"history-search-forward" ); + 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" ); diff --git a/input.h b/input.h index fbb991daf..32406b28f 100644 --- a/input.h +++ b/input.h @@ -49,7 +49,9 @@ enum R_EXECUTE, R_BEGINNING_OF_BUFFER, R_END_OF_BUFFER, - R_REPAINT + R_REPAINT, + R_UP_LINE, + R_DOWN_LINE, } ; diff --git a/parse_util.c b/parse_util.c index 7a767ba0b..8635bc4da 100644 --- a/parse_util.c +++ b/parse_util.c @@ -135,6 +135,97 @@ int parse_util_lineno( const wchar_t *str, int len ) return res; } + +int parse_util_get_line_from_offset( wchar_t *buff, int pos ) +{ + // return parse_util_lineno( buff, pos ); + + int i; + int count = 0; + if( pos < 0 ) + { + return -1; + } + + for( i=0; i= off2-off-1 ) + { + line_offset2 = off2-off-1; + } + + return off + line_offset2; + +} + + int parse_util_locate_cmdsubst( const wchar_t *in, wchar_t **begin, wchar_t **end, diff --git a/parse_util.h b/parse_util.h index e0f4cf261..a1b0b74ec 100644 --- a/parse_util.h +++ b/parse_util.h @@ -93,6 +93,23 @@ void parse_util_token_extent( const wchar_t *buff, */ int parse_util_lineno( const wchar_t *str, int len ); +/** + Calculate the line number of the specified cursor position + */ +int parse_util_get_line_from_offset( wchar_t *buff, int pos ); + +/** + Get the offset of the first character on the specified line + */ +int parse_util_get_offset_from_line( wchar_t *buff, int line ); + + +/** + Return the total offset of the buffer for the cursor position nearest to the specified poition + */ +int parse_util_get_offset( wchar_t *buff, int line, int line_offset ); + + /** Autoload the specified file, if it exists in the specified path. Do not load it multiple times unless it's timestamp changes or diff --git a/reader.c b/reader.c index 0c6d56064..8af223db2 100644 --- a/reader.c +++ b/reader.c @@ -258,6 +258,12 @@ typedef struct reader_data Pointer to previous reader_data */ struct reader_data *next; + + /** + This variable keeps state on if we are in search mode, and + if yes, what mode + */ + int search_mode; } reader_data_t; @@ -681,6 +687,7 @@ void repaint() } + /** Remove the previous character in the character buffer and on the screen using syntax highlighting, etc. @@ -2304,12 +2311,12 @@ wchar_t *reader_readline() int comp_empty=1; int finished=0; struct termios old_modes; - int search_mode = 0; check_size(); sb_clear( &data->search_buff ); data->buff[data->buff_len]='\0'; - + data->search_mode = NO_SEARCH; + s_reset( &data->screen ); exec_prompt(); @@ -2621,9 +2628,9 @@ wchar_t *reader_readline() /* Escape was pressed */ case L'\x1b': { - if( search_mode ) + if( data->search_mode ) { - search_mode= 0; + data->search_mode= NO_SEARCH; if( data->token_history_pos==-1 ) { @@ -2745,23 +2752,23 @@ wchar_t *reader_readline() { int reset = 0; - if( search_mode == NO_SEARCH ) + if( data->search_mode == NO_SEARCH ) { reset = 1; if( ( c == R_HISTORY_SEARCH_BACKWARD ) || - ( c == R_HISTORY_SEARCH_FORWARD ) ) + ( c == R_HISTORY_SEARCH_FORWARD ) ) { - search_mode = LINE_SEARCH; + data->search_mode = LINE_SEARCH; } else { - search_mode = TOKEN_SEARCH; + data->search_mode = TOKEN_SEARCH; } sb_append( &data->search_buff, data->buff ); } - switch( search_mode ) + switch( data->search_mode ) { case LINE_SEARCH: @@ -2874,6 +2881,72 @@ wchar_t *reader_readline() break; } + case R_UP_LINE: + case R_DOWN_LINE: + { + int line = parse_util_get_line_from_offset( data->buff, + data->buff_pos ); + int new_line; + + if( c == R_UP_LINE ) + new_line = line-1; + else + new_line = line+1; + + int line_count = parse_util_lineno( data->buff, data->buff_len )-1; + + if( new_line >= 0 && new_line <= line_count) + { + int base_pos; + + int indent_old; + int indent_new; + int old_line_offset; + int new_total_offset; + +// debug( 0, L"Move up one line to %d", new_line ); + + base_pos = parse_util_get_offset_from_line( data->buff, + new_line ); +/* debug( 0, L"Old cursor offset is %d, new base offset is %d", + data->buff_pos, + base_pos ); +*/ + + if( data->buff_pos ==(data->buff_len) ) + { + if( data->buff_pos == 0 ) + { + indent_old = 0; + } + else + { + indent_old = data->indent[data->buff_pos-1]; + } + } + else + { + if( data->buff[data->buff_pos] == L'\n' ) + indent_old = data->indent[data->buff_pos-1]; + else + indent_old = data->indent[data->buff_pos]; + } + + indent_new = data->indent[base_pos]; + // debug( 0, L"Old indent %d, new indent %d", indent_old, indent_new ); + + old_line_offset = data->buff_pos - parse_util_get_offset_from_line( data->buff, + line ); + new_total_offset = parse_util_get_offset( data->buff, new_line, old_line_offset - 4*(indent_new-indent_old)); + data->buff_pos = new_total_offset; + repaint(); + } + + + break; + } + + /* Other, if a normal character, we add it to the command */ default: { @@ -2896,18 +2969,19 @@ wchar_t *reader_readline() } } - + if( (c != R_HISTORY_SEARCH_BACKWARD) && - (c != R_HISTORY_SEARCH_FORWARD) && - (c != R_HISTORY_TOKEN_SEARCH_BACKWARD) && - (c != R_HISTORY_TOKEN_SEARCH_FORWARD) ) + (c != R_HISTORY_SEARCH_FORWARD) && + (c != R_HISTORY_TOKEN_SEARCH_BACKWARD) && + (c != R_HISTORY_TOKEN_SEARCH_FORWARD) && + (c != R_NULL) ) { - search_mode = 0; + data->search_mode = NO_SEARCH; sb_clear( &data->search_buff ); history_reset(); data->token_history_pos=-1; } - + last_char = c; } @@ -2929,6 +3003,17 @@ wchar_t *reader_readline() return finished ? data->buff : 0; } +int reader_search_mode() +{ + if( !data ) + { + return -1; + } + + return !!data->search_mode; +} + + /** Read non-interactively. Read input from stdin without displaying the prompt, using syntax highlighting. This is used for reading diff --git a/reader.h b/reader.h index 2159deec0..f82d6e88c 100644 --- a/reader.h +++ b/reader.h @@ -174,4 +174,12 @@ int reader_exit_forced(); */ int reader_shell_test( wchar_t *b ); +/** + Test whether the interactive reader is in search mode. + + \return o if not in search mode, 1 if in search mode and -1 if not in interactive mode + */ +int reader_search_mode(); + + #endif diff --git a/share/functions/down-or-search.fish b/share/functions/down-or-search.fish new file mode 100644 index 000000000..f87736664 --- /dev/null +++ b/share/functions/down-or-search.fish @@ -0,0 +1,23 @@ +function down-or-search + # If we are already in search mode, continue + if commandline --search-mode + commandline -f history-search-forward + return + end + + # We are not in search mode. + # If we are on the bottom line, start search mode, + # otherwise move down + set lineno (commandline -L) + set line_count (commandline|wc -l) + + echo on line $lineno of $line_count >&2 + + switch $lineno + case $line_count + commandline -f history-search-forward + + case '*' + commandline -f down-line + end +end diff --git a/share/functions/up-or-search.fish b/share/functions/up-or-search.fish new file mode 100644 index 000000000..94beaa188 --- /dev/null +++ b/share/functions/up-or-search.fish @@ -0,0 +1,17 @@ +function up-or-search + # If we are already in search mode, continue + if commandline --search-mode + commandline -f history-search-backward + return + end + + set lineno (commandline -L) + + switch $lineno + case 1 + commandline -f history-search-backward + + case '*' + commandline -f up-line + end +end