Add experimental support for selection and visual mode

This commit is contained in:
Julian Aron Prenner 2014-01-15 15:07:22 +01:00
parent fc21bb6eda
commit c8d5131a42
10 changed files with 172 additions and 24 deletions

View file

@ -211,6 +211,7 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
int append_mode=0;
int function_mode = 0;
int selection_mode = 0;
int tokenize = 0;
@ -315,6 +316,10 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
L"search-mode", no_argument, 0, 'S'
}
,
{
L"selection", no_argument, 0, 's'
}
,
{
0, 0, 0, 0
}
@ -402,6 +407,10 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
search_mode = 1;
break;
case 's':
selection_mode = 1;
break;
case 'h':
builtin_print_help(parser, argv[0], stdout_buffer);
return 0;
@ -465,6 +474,26 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
return 0;
}
if (selection_mode)
{
size_t sel_start, sel_stop;
const wchar_t *buffer = reader_get_buffer();
if(reader_get_selection_pos(sel_start, sel_stop))
{
size_t len = std::min(sel_stop - sel_start + 1, wcslen(buffer));
wchar_t *selection = new wchar_t[len];
selection = wcsncpy(selection, current_buffer + sel_start, len);
append_format(stdout_buffer, selection);
delete selection;
}
else
{
append_format(stdout_buffer, L"");
}
return 0;
}
/*
Check for invalid switch combinations
*/

View file

@ -70,6 +70,11 @@
*/
#define HIGHLIGHT_AUTOSUGGESTION 0x2000
/**
Internal value representing highlighting an active selection
*/
#define HIGHLIGHT_SELECTION 0x80
class history_item_t;
struct file_detection_context_t;

View file

@ -137,7 +137,9 @@ static const wchar_t * const name_arr[] =
L"up-line",
L"down-line",
L"suppress-autosuggestion",
L"accept-autosuggestion"
L"accept-autosuggestion",
L"begin-selection",
L"end-selection",
}
;
@ -227,7 +229,9 @@ static const wchar_t code_arr[] =
R_UP_LINE,
R_DOWN_LINE,
R_SUPPRESS_AUTOSUGGESTION,
R_ACCEPT_AUTOSUGGESTION
R_ACCEPT_AUTOSUGGESTION,
R_BEGIN_SELECTION,
R_END_SELECTION
}
;
@ -265,7 +269,7 @@ const wchar_t *input_get_bind_mode()
const env_var_t bind_mode_var = env_get_string(FISH_BIND_MODE_VAR);
if(!bind_mode_var.missing())
{
bind_mode = bind_mode_var.c_str();
bind_mode = bind_mode_var.c_str();
}
return bind_mode;
}

View file

@ -61,11 +61,13 @@ enum
R_DOWN_LINE,
R_SUPPRESS_AUTOSUGGESTION,
R_ACCEPT_AUTOSUGGESTION,
R_BEGIN_SELECTION,
R_END_SELECTION
}
;
#define R_MIN R_NULL
#define R_MAX R_ACCEPT_AUTOSUGGESTION
#define R_MAX R_END_SELECTION
/**
Initialize the terminal by calling setupterm, and set up arrays

View file

@ -172,6 +172,13 @@ commence.
History search mode. This value means we are searching forwards.
*/
#define SEARCH_FORWARD 1
/**
The color used to display an active selection
*/
#define FISH_SELECTION_COLOR_VAR L"fish-selection-color"
/** The color used if the variable above is not set */
#define DEFAULT_SELECTION_COLOR L"gray"
/* Any time the contents of a buffer changes, we update the generation count. This allows for our background highlighting thread to notice it and skip doing work that it would otherwise have to do. This variable should really be of some kind of interlocked or atomic type that guarantees we're not reading stale cache values. With C++11 we should use atomics, but until then volatile should work as well, at least on x86.*/
static volatile unsigned int s_generation_count;
@ -258,6 +265,9 @@ public:
/** Indicates whether a selection is currently active */
bool sel_active;
/** The position of the cursor, when selection was initiated. */
size_t sel_begin_pos;
/** The start position of the current selection, if one. */
size_t sel_start_pos;
@ -349,6 +359,7 @@ public:
search_pos(0),
buff_pos(0),
sel_active(0),
sel_begin_pos(0),
sel_start_pos(0),
sel_stop_pos(0),
complete_func(0),
@ -448,9 +459,22 @@ static void term_donate()
/**
Update the cursor position
*/
static void update_buff_pos(int buff_pos)
static void update_buff_pos(size_t buff_pos)
{
data->buff_pos = buff_pos;
if(data->sel_active)
{
if(data->sel_begin_pos <= buff_pos)
{
data->sel_start_pos = data->sel_begin_pos;
data->sel_stop_pos = buff_pos;
}
else
{
data->sel_start_pos = buff_pos;
data->sel_stop_pos = data->sel_begin_pos;
}
}
}
@ -536,7 +560,6 @@ wcstring combine_command_and_autosuggestion(const wcstring &cmdline, const wcstr
commandline, write the prompt, perform syntax highlighting, write
the commandline and move the cursor.
*/
static void reader_repaint()
{
// Update the indentation
@ -552,6 +575,15 @@ static void reader_repaint()
std::vector<color_t> colors = data->colors;
colors.resize(len, HIGHLIGHT_AUTOSUGGESTION);
if(data->sel_active)
{
int selection_color = HIGHLIGHT_SELECTION << 16;
for(int i = data->sel_start_pos; i <= std::min(len - 1, data->sel_stop_pos); i++)
{
colors[i] = selection_color;
}
}
std::vector<int> indents = data->indents;
indents.resize(len);
@ -562,11 +594,14 @@ static void reader_repaint()
data->command_length(),
&colors[0],
&indents[0],
data->buff_pos);
data->buff_pos,
data->sel_start_pos,
data->sel_stop_pos);
data->repaint_needed = false;
}
static void reader_repaint_without_autosuggestion()
{
// Swap in an empty autosuggestion, repaint, then swap it out
@ -606,7 +641,7 @@ static void reader_kill(size_t begin_idx, size_t length, int mode, int newv)
{
/* Move the buff position back by the number of characters we deleted, but don't go past buff_pos */
size_t backtrack = mini(data->buff_pos - begin_idx, length);
data->buff_pos -= backtrack;
update_buff_pos(data->buff_pos - backtrack);
}
data->command_line.erase(begin_idx, length);
@ -1101,7 +1136,7 @@ static void remove_backward()
int width;
do
{
data->buff_pos -= 1;
update_buff_pos(data->buff_pos - 1);
width = fish_wcwidth(data->command_line.at(data->buff_pos));
data->command_line.erase(data->buff_pos, 1);
}
@ -1129,7 +1164,7 @@ static bool insert_string(const wcstring &str, bool should_expand_abbreviations
return false;
data->command_line.insert(data->buff_pos, str);
data->buff_pos += len;
update_buff_pos(data->buff_pos + len);
data->command_line_changed();
data->suppress_autosuggestion = false;
@ -2475,6 +2510,26 @@ size_t reader_get_cursor_pos()
return data->buff_pos;
}
bool reader_get_selection_pos(size_t &start, size_t &stop)
{
if (!data)
{
return false;
}
else
{
if(!data->sel_active)
return false;
else
{
start = data->sel_start_pos;
stop = data->sel_stop_pos;
return true;
}
}
}
#define ENV_CMD_DURATION L"CMD_DURATION"
void set_env_cmd_duration(struct timeval *after, struct timeval *before)
@ -2572,6 +2627,8 @@ int reader_shell_test(const wchar_t *b)
0,
tmp,
tmp2,
0,
0,
0);
@ -2945,7 +3002,7 @@ static int read_i(void)
else if (tmp)
{
wcstring command = tmp;
data->buff_pos=0;
update_buff_pos(0);
data->command_line.clear();
data->command_line_changed();
reader_run_command(parser, command);
@ -3136,7 +3193,7 @@ const wchar_t *reader_readline(void)
while ((data->buff_pos>0) &&
(buff[data->buff_pos-1] != L'\n'))
{
data->buff_pos--;
update_buff_pos(data->buff_pos - 1);
}
reader_repaint();
@ -3150,7 +3207,7 @@ const wchar_t *reader_readline(void)
while (buff[data->buff_pos] &&
buff[data->buff_pos] != L'\n')
{
data->buff_pos++;
update_buff_pos(data->buff_pos + 1);
}
}
else
@ -3174,8 +3231,6 @@ const wchar_t *reader_readline(void)
/* go to EOL*/
case R_END_OF_BUFFER:
{
data->buff_pos = data->command_length();
update_buff_pos(data->command_length());
reader_repaint();
@ -3442,7 +3497,7 @@ const wchar_t *reader_readline(void)
*/
if (data->buff_pos < data->command_length())
{
data->buff_pos++;
update_buff_pos(data->buff_pos + 1);
remove_backward();
}
break;
@ -3496,7 +3551,7 @@ const wchar_t *reader_readline(void)
}
}
finished=1;
data->buff_pos=data->command_length();
update_buff_pos(data->command_length());
reader_repaint();
break;
}
@ -3617,7 +3672,7 @@ const wchar_t *reader_readline(void)
{
if (data->buff_pos > 0)
{
data->buff_pos--;
update_buff_pos(data->buff_pos - 1);
reader_repaint();
}
break;
@ -3628,7 +3683,7 @@ const wchar_t *reader_readline(void)
{
if (data->buff_pos < data->command_length())
{
data->buff_pos++;
update_buff_pos(data->buff_pos + 1);
reader_repaint();
}
else
@ -3760,7 +3815,7 @@ const wchar_t *reader_readline(void)
/* If the cursor is at the end, transpose the last two characters of the line */
if (data->buff_pos == data->command_length())
{
data->buff_pos--;
update_buff_pos(data->buff_pos - 1);
}
/*
@ -3783,8 +3838,11 @@ const wchar_t *reader_readline(void)
const wchar_t *tok_begin, *tok_end, *prev_begin, *prev_end;
/* If we are not in a token, look for one ahead */
while (data->buff_pos != len && !iswalnum(buff[data->buff_pos]))
data->buff_pos++;
size_t buff_pos = data->buff_pos;
while (buff_pos != len && !iswalnum(buff[buff_pos]))
buff_pos++;
update_buff_pos(buff_pos);
parse_util_token_extent(buff, data->buff_pos, &tok_begin, &tok_end, &prev_begin, &prev_end);
@ -3852,6 +3910,23 @@ const wchar_t *reader_readline(void)
break;
}
case R_BEGIN_SELECTION:
{
data->sel_active = true;
data->sel_begin_pos = data->buff_pos;
data->sel_start_pos = data->buff_pos;
data->sel_stop_pos = data->buff_pos;
break;
}
case R_END_SELECTION:
{
data->sel_active = false;
data->sel_start_pos = data->buff_pos;
data->sel_stop_pos = data->buff_pos;
break;
}
/* Other, if a normal character, we add it to the command */
default:
{

View file

@ -114,6 +114,13 @@ void reader_set_buffer(const wcstring &b, size_t p);
*/
size_t reader_get_cursor_pos();
/**
Get the current selection range in the command line.
Returns false if there is no active selection, true otherwise.
*/
bool reader_get_selection_pos(size_t &start, size_t &stop);
/**
Return the value of the interrupted flag, which is set by the sigint
handler, and clear it if it was set.

View file

@ -1234,7 +1234,9 @@ void s_write(screen_t *s,
size_t explicit_len,
const int *colors,
const int *indent,
size_t cursor_pos)
size_t cursor_pos,
size_t sel_start_pos,
size_t sel_stop_pos)
{
screen_data_t::cursor_t cursor_arr;

View file

@ -181,6 +181,8 @@ public:
\param colors the colors to use for the comand line
\param indent the indent to use for the command line
\param cursor_pos where the cursor is
\param sel_start_pos where the selections starts (inclusive)
\param sel_stop_pos where the selections ends (inclusive)
*/
void s_write(screen_t *s,
const wcstring &left_prompt,
@ -189,7 +191,9 @@ void s_write(screen_t *s,
size_t explicit_len,
const int *colors,
const int *indent,
size_t cursor_pos);
size_t cursor_pos,
size_t sel_start_pos,
size_t sel_stop_pos);
/**
This function resets the screen buffers internal knowledge about

View file

@ -28,6 +28,7 @@ function fish_vi_key_bindings -d "vi-like key bindings for fish"
bind -m insert I beginning-of-line force-repaint
bind -m insert a forward-char force-repaint
bind -m insert A end-of-line force-repaint
bind -m visual v begin-selection force-repaint
bind -m insert o "commandline -a \n" down-line force-repaint
#bind -m insert O beginning-of-line "commandline -i \n" up-line force-repaint # doesn't work
@ -148,4 +149,20 @@ function fish_vi_key_bindings -d "vi-like key bindings for fish"
bind -M insert \cd exit
bind -M insert \ef forward-word
#
# visual mode
#
bind -M visual \e\[C forward-char
bind -M visual \e\[D backward-char
bind -M visual -k right forward-char
bind -M visual -k left backward-char
bind -M visual h backward-char
bind -M visual l forward-char
bind -M visual -m default \cc end-selection force-repaint
bind -M visual -m default \e end-selection force-repaint
end

View file

@ -7,6 +7,9 @@ function fish_vi_prompt_cm --description "Displays the current mode"
case insert
set_color --bold --background red white
echo "[I]"
case visual
set_color --bold --background magenta white
echo "[V]"
end
set_color normal
end